5. Longest Palindromic Substring

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example:

Input: "babad"

Output: "bab"

Note: "aba" is also a valid answer.
Example:

Input: "cbbd"

Output: "bb"
Show Company Tags
Show Tags
Show Similar Problems

S1: naive enumeration
以每个字符为轴往左右查找palindromic substring

    string longestPalindrome(string s) {
        int size = s.size();
        if(size < 1) return "";
        string substring = s.substr(0,1);
        for(int i = 1; i < size; ++i){
            if(s[i] == s[i-1]){
                int j = 1;
                while(i+j < size && i-j > 0 && s[i+j] == s[i-j-1]) j++;
                if(2*j > substring.size()) substring = s.substr(i-j, 2*j);
            }
            if(i - 2 >= 0 && s[i] == s[i-2]){
                int j = 1;
                while(i+j< size && i-2-j >= 0 && s[i+j] == s[i-2-j]) j++;
                if(2*j+1 > substring.size()) substring = s.substr(i-j-1, 2*j+1);
            }
        }
        return substring;
    }

S2:enumeration with prunning

如果子串中有许多连续重复字母的话,可以进一步优化。最长回文子串的对称轴一定处在任意个连续的重复字母的中心。不然会导致回文子串短于这些连续字母。
这样可以每次扫描一段连续重复字母的左右位置,作为扩展的起始位置。

    string longestPalindrome(string s) {
        string result = "";
        for (int left = 0, right = left; left < s.size(); left = right) {
            right = left + 1;
            //跳过重复字符
            while (right < s.size() && s[right] == s[right-1]) {
                right++;
            }
            //尝试向两边扩张
            int curLeft = left - 1, curRight = right; 
            while (curLeft >= 0 && curRight < s.size() && s[curLeft] == s[curRight]) {
                curLeft--;
                curRight++;
            }
            int len = curRight - curLeft - 1;
            if (len > result.size()) {
                result = s.substr(curLeft + 1, len);
            }
        }
        return result;
    }

S3: DP

isPal[i][j]表示s[j]到s[i]是palindrome

//error注意:没有通过aabaaa的test case, output "maaa"没看出来为何
    string longestPalindrome(string& s) {
        string result = "";
        int n = s.size();
        if (n <= 1) {
            return s;
        }
        vector<vector<bool>> isPal(n, vector<bool>(n, false));
        isPal[0][0] = true;
        for (int i = 1; i < n; ++i) {
            isPal[i][i] = true;
            isPal[i][i-1] = s[i] == s[i-1];
            if (isPal[i][i-1] && result.size() < 2) {
                result = s.substr(i-1, 2);
            }
            for (int j = i - 2; j >= 0; --j) {
                isPal[i][j] = (isPal[i-1][j+1] && s[i] == s[j]);
                if (isPal[i][j] && j - i + 1 > result.size()) {
                    result = s.substr(j, i - j + 1);
                }
            }
        }
        return result;
    }

214. Shortest Palindrome

Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.

For example:

Given "aacecaaa", return "aaacecaaa".

Given "abcd", return "dcbabcd".

S1: naive enumeration
从数组的中间开始,穷举所有以s[i]为中心的palindrome,直到得到结果。注意s[i]取最优解的情况是以s[i+1]为轴而不是以s[i]和s[i+1]之间为轴。

    string shortestPalindrome(string s) {
        int size = s.size();
        for(int mid = size/2-1; mid >= 0; --mid){
            int j = 0;
            while(mid-j >= 0 && mid+2+j < size && s[mid-j] == s[mid+2+j]) j++;
            if(mid-j < 0){
                string result = "";
                for(int i = size-1; i >= 2*mid+3; --i)
                    result += s[i];
                result += s;
                return result;
            }
            else{
                j = 0;
                while( mid-j >= 0 && mid+1+j < size && s[mid-j] == s[mid+1+j]) j++;
                if(mid-j < 0){
                    string result = "";
                    for(int i = size-1; i >= 2*(mid+1); --i)
                        result += s[i];
                    result += s;
                    return result;
                }
            }
        }
        string result = "";
        for(int i = size-1; i > 0; --i) result += s[i];
        result += s;
        return result;
    }

S2: KMP trick

只用找到从0开始的最长palindrome,再把剩下的字符reverse贴到前面即可。

比如abacd, aba是从0开始的最长palindrome, 只用把cd翻转为dc贴到前边得到dcabacd就是答案。

求从0开始的最长palindrome,trick是构造一个新string l = s + '#' + reverse(s),然后参考KMP算法中构造lps:longest proper prefix which is also suffix 的过程。(这里假设#不在原string中,#是为了在reverse(s)开始的时候将len清零)

    string shortestPalindrome(string s) {
        string rs(s.rbegin(), s.rend());
        string l = s + '#' + rs;
        vector<int> table(l.size(), 0);
        int len = 0, i = 1, size = s.size();
        while( i < l.size()){
            if(l[i] == l[len]){
                len++;
                table[i] = len;
                i++;
            }
            else if(len > 0){
                len = table[len-1];//???
            }
            else{
                table[i] = 0;
                i++;
            }
        }
        return l.substr(size+1, size-table[l.size()-1])+s;
    }

266. Palindrome Permutation

Given a string, determine if a permutation of the string could form a palindrome.

For example,
"code"-> False,"aab"-> True,"carerac"-> True.

S: bitset O(n)

只能有最多一个char出现奇数次,即出现在中间

    bool canPermutePalindrome(string s) {
        bitset<256> count;
        for (char c : s) {
            count.flip(c);
        }
        return count.count() < 2;
    }

409. Longest Palindrome

Given a string which consists of lowercase or uppercase letters, find the length of the longest palindromes that can be built with those letters.

This is case sensitive, for example"Aa"is not considered a palindrome here.

S: O(n)

最多只有一个char出现奇数次,其他出现奇数次的char都要减一

    int longestPalindrome(string s) {
        unordered_map<char, int> count;
        for (char c : s) count[c]++;
        int len = 0;
        bool hasOdd = false;
        for (auto i : count) {
            if (i.second & 1) {
                hasOdd = true;
                len += i.second - 1;
            } else len += i.second;
        }
        return hasOdd? len + 1 : len;
    }

336. Palindrome Pairs

Given a list ofuniquewords, find all pairs ofdistinctindices(i, j)in the given list, so that the concatenation of the two words, i.e.words[i] + words[j]is a palindrome.

Example 1:
Givenwords=["bat", "tab", "cat"]
Return[[0, 1], [1, 0]]
The palindromes are["battab", "tabbat"]

Example 2:
Givenwords=["abcd", "dcba", "lls", "s", "sssll"]
Return[[0, 1], [1, 0], [3, 2], [2, 4]]
The palindromes are["dcbaabcd", "abcddcba", "slls", "llssssll"]
S1: brutal force O(n^2)

S2: hash map O(n*k^2) n is the size of word list, k is the average size of each word

关键是如何快速找到匹配的word:

  1. 反转每个词语存入hash map作为key,value为index
  2. 将word拆分为 left | right 两部分,只需要找到candidate满足candidate = left且right为palindrome(left|right|candidate) 或者 candidate = right且left为palindrome(candidate|left|right) 注意当中间那部分为空时会出现重复,只计算一次
class Solution {
public:
    vector<vector<int>> palindromePairs(vector<string>& words) {
        unordered_map<string, int> revMap;
        vector<vector<int>> result;
        for (int i = 0; i < words.size(); ++i) {
            string s = words[i];
            reverse(s.begin(), s.end());
            revMap[s] = i;
        }
        for (int i = 0; i < words.size(); ++i) {
            int n = words[i].size();
            for (int j = 0; j <= n; ++j) {
                string left = words[i].substr(0, j);
                string right = words[i].substr(j, n - j);
                if (revMap.find(left) != revMap.end() && revMap[left] != i &&isPal(right)) {  //left|right|candidate
                    result.push_back(vector<int>{i, revMap[left]});
                }
                if (left.size() > 0 && revMap.find(right) != revMap.end() && revMap[right] != i 
                    && isPal(left)) { //candidate|left|right
                    result.push_back(vector<int>{revMap[right], i});
                }
            }
        }
        return result;
    }

    bool isPal(string s) {
        int left = 0, right = s.size() - 1;
        while (left < right) {
            if (s[left++] != s[right--]) return false;
        }
        return true;
    }
};

results matching ""

    No results matching ""