LeetCode5. Longest Palindromic Substring 最长子回文串

最长子回文串

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"
动态规划

如果一个字符串为回文串,那么除去他的首尾一个字符,得到的新字符依旧是回文串。即对于一个字符串S有

p(i,j) = p(i+1,j-1) and Si = Sj。P(i,j)表示从i到j的字符串。

从表达式可以看出,需要知道p(i,j),必须先知道p(i+1,j-1)。不如将外层循环倒置过来,先求i+1的值,再求j-1的值。

还有一点要注意的是初始值,关于j - i < 3。如果长度为1的话,那么这个字符串必然为回文串,如果长度为2的话,又满足Si = Sj 那么他也必然是回文串。即他们不受上述表达式的约束。

public String longestPalindrome(String s) {
    if(s == null || s.length() < 1){
        return "";
    }
    int len = s.length();
    boolean[][] dp = new boolean[len][len];
    int subLength = 0;
    String res = null;
    for(int i = len - 1; i>= 0 ;i--){
        for(int j = i; j < len; j++){
            dp[i][j] = s.charAt(i) == s.charAt(j) &&(j - i < 3 || dp[i+1][j-1]);
            
            if(dp[i][j] && (res == null || j - i + 1 > res.length())){
                res = s.substring(i,j+1);
            }
        }
    }
    return res;
}
中心扩展算法

首先先看一下回文串有什么特点,回文串的最大特点就是中心对齐。如“ababa",他是以a为中心对齐。那么对于“abba”这种偶数的回文串,同样也是中心对齐的。他以两个b之间的字符之间为中心。因此我们可以以数组的每一个元素作为中心,找出最大的回文串。

我们可以设置回文串的头尾指针,start 和 end。如果有比目前的回文串更长的回文串,则修改start和end的的位置。这样子时间复杂度为O(n^2),空间复杂度为O(n)。

扫描二维码关注公众号,回复: 9200433 查看本文章
public String longestPalindrome(String s) {
    if(s == null || s.length() < 1){
        return "";
    }
    int sLen = s.length();
    int start = 0,end = 0;
    for(int i = 0; i < sLen; i++){
        int len1 = expandAroundCenter(s,i,i);
        int len2 = expandAroundCenter(s,i,i+1);
        int len = Math.max(len1,len2);
        if(len > end - start){
            start = i - (len - 1)/2;
            end = i + len/2;
        }
    }
    return s.substring(start,end+1);
}

private int expandAroundCenter(String s,int left,int right){
    int L = left,R = right;
    while(L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)){
        L--;
        R++;
    }
    return R - L -1;
}
马拉车算法(Manacher’s Algorithm)

马拉车算法充分应用了回文串的对称性。和中心扩展法一样,我们以某个节点为中心,分别向两边扩展。为了保持字符的个数为奇数,在字符与字符之间插入特殊符号“#”来保证出力的字符个数是为奇数的。如“abab”变为“#a#b#a#b#”。假设新的字符串为T,我们使用P[i] 表示 T[i]处的回文半径。如以T[i]为中心的最长回文串为T[l,r],则P[i] = r - i + 1。这样求最长回文串的问题就转换为求数组P的问题了。

数组P怎么求,考虑。center 表示之前取得最大回文串的中心位置。right表示最大回文串能到达的最右端的值。

  1. 若i<right,则i之前的值必然计算出来了。我们可以利用回文串的性质。找出点i关于center的对称点j。j = 2* center - i。
    1. 如果P[j] < right -i。即以j为中心的回文串没有超出[left,right]的范围,由回文串的性质知道,两端的对应字符应该是相等的。所以有P[j] = P[i]。
    2. 如果P[j] >= right -i。即表明以j为中心的最大回文串超出了范围。在范围内的部分肯定是复合回文串的性质,但是对于超出的部分,只要从right+1开始一一匹配,从而更新right和对应的center,
  2. 若i > right 无法利用回文串的性质,只能一步一步去匹配。
 public String longestPalindrome(String s) {
        if(s == null || s.length() < 1){
            return s;
        }
        int sLen = s.length();
        StringBuilder t = new StringBuilder();
        // t.append("$");
        t.append("#");
        for(int i = 0; i < sLen; i++){
            t.append(s.charAt(i));
            t.append("#");
        } 
     
        int tLen = t.length();
        int center = 0;
        int right = 0;
        int maxCenter =0;
        int maxLen = 1;
        
        int[] p = new int[2 *sLen + 1];
        for(int i = 0; i < tLen; ++i){
            
            p[i] = i<right?Math.min(p[2*center -i],right -i):1;
            
            while(i - p[i] >= 0 && i + p[i]<tLen && t.charAt(i - p[i]) == t.charAt(i + p[i])){
                p[i]++;
                
            }
            
            if(right < i + p[i]){
                right = i + p[i];
                center = i;
            }
            
            if(maxLen < p[i]){
                maxLen = p[i];
                maxCenter = i;
            }
            
        }        
        return s.substring((maxCenter - maxLen + 1)/2,(maxCenter - maxLen + 1)/2 + maxLen - 1);
    }
发布了36 篇原创文章 · 获赞 8 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_32763643/article/details/104046324