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, and there exists one unique longest palindromic substring.

http://www.lintcode.com/en/problem/longest-palindromic-substring/

Discussion


这个题有很多种解法。暴力,动规。要熟悉。

Sulution 1


Brute force。判断每一个substring是否为palindrome,返回最长的那个。总共有C(N,2)个substring,判断回文复杂度为O(N)。所以是$$O(N^3)$$ 的runtime,O(1) space。

判断回文的方法见题目Valid Palindrome

substr函数

class Solution {
public:
    /**
     * @param s input string
     * @return the longest palindromic substring
     */
    string longestPalindrome(string& s) {
        // Write your code here
        int n = s.length();
        int maxlen = 0;
        string result;
        for (int i=0; i<n; i++) {
            for(int j=i; j<n; j++) {
                //string tmp (s.begin()+i, s.begin()+j);//当i=j时,tmp是空的,所以不行,用substr函数。
                string tmp = s.substr(i, j-i+1);
                if(isPalindrome(tmp)) {
                    if(tmp.length() > maxlen) {
                        maxlen = tmp.length();
                        result = tmp;
                    }
                }
            }
        }
        return result;
    }
private:
    bool isPalindrome(string& s) {
        // Write your code here
        if (s.length()==0)
            return true;
        int begin = 0;
        int end = s.length()-1;
        while(begin< end) {
            if(isalnum(s[begin]) == false)
                begin++;
            if(isalnum(s[end]) == false) 
                end--;
            if(begin>=end)
                break;
            if(tolower(s[begin]) != tolower(s[end]) ) 
                return false;
            begin++;
            end--;
        }
        return true;
    }
};

Solution 2

DP.

  • state: f[i][j]表示从i到j的substring是回文
  • 状态转移:f[i][j] = f[i+1][j-1] && s[i]==s[j]. aba是回文是因为b是回文,两头两个a相同。
  • initialize: f[i][i]=true, f[i][i+1]= (s[i]==s[i+1])
  • answer: 记录最大长度和开始结束位置。

用一个string"ababa"画状态转移图,coding就不难了。

O(n^2) runtime, O(n^2) space.

class Solution {
public:
    /**
     * @param s input string
     * @return the longest palindromic substring
     */
    string longestPalindrome(string& s) {
        string result;
        if(s.length() ==0) return result;
        int n = s.length();
        int max_len = 1;
        vector<vector<bool>> is_palindrome(n, vector<bool>(n, false));
        int start_pos = 0;
        for(int i=0; i<n-1; i++) {
            is_palindrome[i][i] = true;
            if(s[i]==s[i+1]) {
                is_palindrome[i][i+1] = true;
                max_len = 2;
                start_pos = i;
            }
        }
        is_palindrome[n-1][n-1] = true;
        for(int i=n-1; i>=0; i--) {
            for(int j=i+2; j<n; j++) {
                if(s[i]==s[j] && is_palindrome[i+1][j-1]) {
                    is_palindrome[i][j] = true;
                    if(j-i+1 > max_len) {
                        max_len = j-i+1;
                        start_pos = i;
                    }
                }
            }
        }
        return s.substr(start_pos, max_len);
    }

};

用滚动数组加自底向上的递归来改进为O(n) space。根据状态转移的实际例子是不难想出滚动数组的使用的。

class Solution {
public:
    /**
     * @param s input string
     * @return the longest palindromic substring
     */
    string longestPalindrome(string& s) {
        // Write your code here
        int n = s.length();
        vector<bool> f(n, false);
        int maxlen = 0;
        int start = 0; 
        int end = 0;
       // f[0] = true;
        for(int j=0; j<n; j++) {
            for (int i=0; i<=j; i++) {
                if(i==j) {
                    f[i] = true;
                } else if (j-i ==1) {
                    f[i] = (s[i] == s[i+1]);
                } else {
                    f[i] = (s[i]==s[j] && f[i+1]);
                }
                if(f[i] && maxlen<j-i+1) {
                    maxlen = j-i+1;
                    start = i;
                    end = j;
                }
            }
        }
        return s.substr(start, end-start+1);
    }
};

Solution 3

可以从一个给定位置,或者两个相邻的给定位置,往两侧扩展,得到新的substring回文。O(n^2) runtime, O(1) space.

class Solution {
public:
    /**
     * @param s input string
     * @return the longest palindromic substring
     */
    string longestPalindrome(string& s) {
        // Write your code here

        int n=s.length();
        string result;
        for(int i=0; i<n; i++) {
            string odd, even;
            odd = extendPalindrome(s, i, i);
            if(i<n-1)
                even = extendPalindrome(s, i, i+1);
            if(odd.length() > result.length()) {
                result = odd;
            }
            if(even.length() > result.length()) {
                result = even;
            }
        }
        return result;
    }
private: 
    string extendPalindrome(string s, int start, int end) {
        bool ind = false;
        string result;
        while (start <=end && start >=0 && end<s.length()) {
            if(s[start] == s[end]) {
                start--;
                end++;
                ind = true;
            } else {
                break;
            }
        }
        if(ind) {
            start++;//这里容易漏掉,防止出错的办法就是根据一个实例写code。
            end--;
            result = s.substr(start, end-start+1);;
        }
        return result;
    }
};

这个思路更简洁的写法:

string expandAroundCenter(string s, int c1, int c2) {
  int l = c1, r = c2;
  int n = s.length();
  while (l >= 0 && r <= n-1 && s[l] == s[r]) {
    l--;
    r++;
  }
  return s.substr(l+1, r-l-1);
}

string longestPalindromeSimple(string s) {
  int n = s.length();
  if (n == 0) return "";
  string longest = s.substr(0, 1);  // a single char itself is a palindrome
  for (int i = 0; i < n-1; i++) {
    string p1 = expandAroundCenter(s, i, i);
    if (p1.length() > longest.length())
      longest = p1;

    string p2 = expandAroundCenter(s, i, i+1);
    if (p2.length() > longest.length())
      longest = p2;
  }
  return longest;
}

如果严格按照一个test case写code,会发现好多details,根据思想直接写是很难考虑到这些details的。养成test case的习惯。。。

竟然还有O(n)的算法,见reference 【2】。

Reference

  1. Longest Palindromic Substring Part I
  2. Longest Palindromic Substring Part II

results matching ""

    No results matching ""