Fork me on GitHub

中等-5-最长回文子串

LeetCode5

给定一个字符串 s,找到 s 中最长的回文子串。

 

一、暴力解法

最暴力的解法是判断s的每个子串是否为回文串,复杂度为立方级,在此不做实现。

这里实现的是中心扩散的思想,即利用回文串中心对称的性质,遍历s的每个字符,其作为回文串的中心,依次向两边扩展更新当前回文串,若超过res则更新res。

复杂度为O(n2)。

以下代码花了几分钟写的,未优化。

class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        String res = "";
        if(len==0) return res;
        int resLen = 0;
     // 奇回文子串
for(int i=0; i<len; i++){ int cur = 1; int left = i-1; int right = i+1; while(left>=0&&right<=len-1&&s.charAt(left)==s.charAt(right)){ left--; right++; cur += 2; } if(cur>resLen){ resLen = cur; res = s.substring(++left,right); } }
     // 偶回文子串
for(double i=0.5; i<=len-1.5; i++){ int cur = 0; int left = (int) (i-0.5); int right = (int) (i+0.5); while(left>=0&&right<=len-1&&s.charAt(left)==s.charAt(right)){ left--; right++; cur += 2; } if(cur>resLen){ resLen = cur; res = s.substring(++left,right); } } return res; } }

 

 

二、动态规划

dp[i][j] 表示 s[i,j](两边闭)是否为回文串。   状态转移方程: dp[i][j] = (s[i] == s[j]) && dp[i + 1][j - 1]。

初始化二维数组对角线为true,并只需维护该对角线以上部分,注意临界范围为 j-i<3 。若该区间为true且长度大于res,则更新目标值。

class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        if(len < 2) return s;
        int resLen = 1;
        int begin = 0;
        boolean[][] dp = new boolean[len][len];
        for(int i=0; i<len; i++)
            dp[i][i] = true;
        for(int j=1; j<len; j++){
            for(int i=0; i<j; i++){
                if(s.charAt(i)!=s.charAt(j)){
                    dp[i][j] = false;
                } else {
                    if(j - i < 3)
                        dp[i][j] = true;
                    else dp[i][j] = dp[i+1][j-1];
                }
                if(dp[i][j] && j - i + 1 > resLen){
                    resLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substring(begin,begin + resLen);
    }
}

 

三、马拉车算法 Manacher' algorithm

参考链接

 构造T为新字符数组,在每个字符两边加上‘#’,长度n+(n+1)统一为奇回文。 构造P数组对应以T中每个字符为中心的回文串长度。

1、最大半径减1等于最长回文串的长度

2、最长回文字符的起始位置(字符串s中的索引)是中间位置(P或T中的索引)减去半径(P中的值+1)再除以2

这里的P数组是长度,因此无需与半径做转换。

 public class Solution {
      // Transform S into T.
      // For example, S = "abba", T = "^#a#b#b#a#$".
      // ^ and $ signs are sentinels appended to each end to avoid bounds checking
      String preProcess(String s) {
          int n = s.length();
          if (n == 0) return "^$";
  
          String ret = "^";
         for (int i = 0; i < n; i++)
         {
             ret += "#" + s.substring(i, i + 1);
         }
         
         ret += "#$";
         return ret;
     }
     public String longestPalindrome(String s) {
         String T = preProcess(s);
         int length = T.length();
         int[] p = new int[length];
         int C = 0, R = 0;
         
         for (int i = 1; i < length - 1; i++)
         {
             int i_mirror = C - (i - C);
             int diff = R - i;
             if (diff >= 0)//当前i在C和R之间,可以利用回文的对称属性
             {
                 if (p[i_mirror] < diff)//i的对称点的回文长度在C的大回文范围内部
                 { p[i] = p[i_mirror]; }
                 else
                 {
                     p[i] = diff;
                     //i处的回文可能超出C的大回文范围了
                     while (T.charAt(i + p[i] + 1) == T.charAt(i - p[i] - 1))
                     { p[i]++; }
                     C = i;
                     R = i + p[i];
                 }
             }
             else
             {
                 p[i] = 0;
                 while (T.charAt(i + p[i] + 1) == T.charAt(i - p[i] - 1))
                 { p[i]++; }
                 C = i;
                 R = i + p[i];
             }
         }
 
         int maxLen = 0;
         int centerIndex = 0;
         for (int i = 1; i < length - 1; i++) {
             if (p[i] > maxLen) {
               maxLen = p[i];
               centerIndex = i;
             }
         }
         return s.substring((centerIndex - 1 - maxLen) / 2, (centerIndex - 1 - maxLen) / 2 + maxLen);        
     }
 }

 

posted @ 2020-08-07 17:56  Faded828x  阅读(113)  评论(0编辑  收藏  举报