• 中等-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);        
         }
     }
  • 相关阅读:
    命令安装mongod作为服务启动
    npm命令
    win服务
    win进程操作
    【数据结构与算法之美】7.排序算法之冒泡、选择、插入
    【leetcode】23.合并K个排序链表
    【leetcode】141.环形链表
    【数据结构与算法之美】6.环形队列
    【数据结构与算法之美】5.基于链表实现队列
    【数据结构与算法之美】4.基于数组实现队列
  • 原文地址:https://www.cnblogs.com/faded828x/p/13454377.html
Copyright © 2020-2023  润新知