LeetCode #5 Longest Palindrome
Description
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Sample
Input: "babad" Output: "bab" Note: "aba" is also a valid answer.
Input: "cbbd" Output: "bb"
思路
回文串是正著讀、反著讀都一樣的串,比如 "a"、"level"、"noon"。
解本道題最無腦的辦法肯定是 O(n^3) ,這裏不討論了。
我想到了一個 O(n^2) 的辦法,由於回文串都是對稱的,那麽它的中點就十分關鍵,我們維護一個指針 i 指向回文串的中點,維護一個指針 j 確定回文串的長度,判斷序列 S[ i-j .. i ] 與序列 S[ i .. i+j ] 的逆序列S‘ 是否相同,如果相同,讓 j++。
舉個例子,如 abcba ,當 i = 2 (S[2] = c) 時,j 賦值為 1,使得 s[ i-1..i ] 與 s[ i..i+1 ] 的逆序列分別為 [bc]、[bc] ,兩者是相同的,那麽就讓 j++ 以表示回文串的長度增加,之後再比較 S[i-2..i] 與 s[i..i+2] 的逆序列是否相同...
還需要註意回文串的長度分奇偶,比如 "bb"、"bab" ,敲代碼的時候也要分別對兩種情況進行修改。
我用 map 去優化這道題存儲回文串的運行時間,紅黑樹實現的map 插入效率為 O(lgn) ,但是算法時間的上界主要受指針 i j 的影響,,所以算法的時間復雜度為 O(n^2 ) ,這兒我想玩玩 map 的比較函數,所以時間會久一點。實際上,用兩個變量存儲最大回文串的長度與最長回文串就好了。
#include<iostream> #include<algorithm> #include<map> using namespace std;class Solution { public: string longestPalindrome(string s) { int len = 0, maxlen = 0; std::map<int, string, greater<int> > m; //use greater<> sort key instead of default less<> string substr = ""; for (int i = 0; i < s.size(); ++i) { findPal(s, i-1, i+1, len, substr); // Palindrome is adjacent if (maxlen < len) { maxlen = len; m[len] = substr; } findPal(s, i, i+1, len, substr); // Palindrome is not adjacent if (maxlen < len) { maxlen = len; m[len] = substr; } } substr = m.begin()->second; //the first value means longestPalindrome return substr; } private: void findPal(const string& s, int left, int right, int& len, string& substring) { while (left >= 0 && right <= s.size()-1 && s[left] == s[right]) { left--; right++; } len = right -left -1; //subtract extra two lengths if (len < 1) return; //length of Palindrome must >= 1 else substring = s.substr(left+1, len); } };
其實還有一種辦法可以更快,那就是采用 區間DP 的 manacher 算法。但是我沒悟到,之後理解了會再更新這篇博客。
LeetCode #5 Longest Palindrome