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 1:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Example 2:

Input: "cbbd"
Output: "bb"

把input string裡每個char位置都當作一個palindrome中心點往左右擴張看是否能形成palindrome,要考慮形成的palindrome長度為奇數和偶數的情形。

// Expand from the center
string longestPalindrome(string s) { // time: O(n^2); space: O(1)
    int n = s.size(), start = 0, max_len = 0;
    if (n < 2) return s;
    for (int i = 0; i < n; ++i) {
        helper(s, i, i, start, max_len); // odd length
        helper(s, i, i + 1, start, max_len); // even length
    }
    return s.substr(start, max_len);
}
void helper(string& s, int l, int r, int& start, int& max_len) {
    while (l >= 0 && r < s.size() && s[l] == s[r]) {
        --l, ++r;
    }
    if (max_len < r - l - 1) {
        max_len = r - l - 1;
        start = l + 1;
    }
    return;
}

利用Dynamic programming的概念搭配一個2D vector掃描所有可能的palindrome組合,dp[i][j]代表string[i...j]是否為palindrome。 (i) dp[i][j] = true if i == j (ii) dp[i][j] = s[i] == s[j] if j = i + 1 (iii) dp[i][j] = s[i] == s[j] && dp[i + 1][j - 1] if j > i + 1

// Dynamic programming
string longestPalindrome(string s) { // time: O(n^2); space: O(n^2)
    int n = s.size(), start = 0, max_len = 0;
    vector<vector<bool> > dp(n, vector<bool>(n, false)); // dp[i][j] means s[i...j] is palindrome
    for (int i = n - 1; i >= 0; --i) {
        for (int j = i; j < n; ++j) {
            dp[i][j] = (s[i] == s[j] && (j - i <= 2 || dp[i + 1][j - 1]));
            if (dp[i][j] && j - i + 1 > max_len) {
                start = i;
                max_len = j - i + 1;
            }
        }
    }
    return s.substr(start, max_len);
}
// Dynamic programming
string longestPalindrome(string s) { // time: O(n^2); space: O(n^2)
    int n = s.size(), start = 0, max_len = 1;
    vector<vector<bool> > dp(n, vector<bool>(n, false)); // dp[i][j] meas s[i...j] is palindrome
    for (int j = 0; j < n; ++j) {
        dp[j][j] = true;
        for (int i = j - 1; i >= 0; --i) {
            dp[i][j] = (s[i] == s[j]) && (j - i <= 2 || dp[i + 1][j - 1]);
            if (dp[i][j] && j - i + 1 > max_len) {
                start = i;
                max_len = j - i + 1;
            }
        }
    }
    return s.substr(start, max_len);
}

Manacher演算法能達到O(n) time complexity。

// Manacher
string longestPalindrome(string s) { // time: O(n); space: O(n)
    // insert $#
    string t = "$#";
    for (char c : s) {
        t += c;
        t += '#';
    }
    // process palindromic radius array
    vector<int> p(t.size(), 0);
    int mx = 0, id = 0, resLen = 0, resCenter = 0;
    for (int i = 1; i < t.size(); ++i) {
        p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
        while (t[i + p[i]] == t[i - p[i]]) ++p[i];
        if (mx < i + p[i]) {
            mx = i + p[i];
            id = i;
        }
        if (resLen < p[i]) {
            resLen = p[i];
            resCenter = i;
        }
    }
    return s.substr((resCenter - resLen) / 2, resLen - 1);
}
// Manacher Algorithm
string longestPalindrome(string s) { // time: O(n); space: O(n)
    string t = "$#";
    for (char c : s) {
        t += c;
        t += '#';
    }
    vector<int> P(t.size(), 0);
    int C = 0, R = 0, resC = 0, resLen = 0;
    for (int i = 1; i < t.size(); ++i) {
        int mirr = 2 * C - i;
        if (i < R) P[i] = min(R - i, P[mirr]);
        while(t[i + (P[i] + 1)] == t[i - (P[i] + 1)]) ++P[i];
        if (i + P[i] > R) {
            C = i;
            R = i + P[i];
        }
        if (resLen < P[i]) {
            resLen = P[i];
            resC = i;
        }
    }
    // cout << resLen << " " << resC;
    return s.substr((resC - resLen) / 2, resLen);
}

Last updated

Was this helpful?