zoukankan      html  css  js  c++  java
  • LeetCode最长回文子串

    题目:
    给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
    示例 1:
    输入: "babad"
    输出: "bab"
    注意: "aba" 也是一个有效答案。

    示例 2:
    输入: "cbbd"
    输出: "bb"
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/longest-palindromic-substring
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
     
    方法一:将字符串倒置 ,找出公共字符串子串->确定最后碰到了自己
    StringBuilder strR=new StringBuilder(s).reverse();//倒置
                int len=s.length();
                int[][] arr=new int[len][len];
                int maxlen=0;
                int startIndex=0;
                
                for(int i=0;i<len;i++) {
                    for(int j=0;j<len;j++) {
                        if(s.charAt(i)==strR.charAt(j)) {
                            if(i==0||j==0) arr[i][j]=1;//边界
                                else arr[i][j]=arr[i-1][j-1]+1;
                        }
    //len-j-1+arr[i][j]-1==j    j(末尾的下标)-(len-j-1)(表示正着的开头下标)+1==arr[i][j](长度)
                        if((len-j-1+arr[i][j]-1==i)&&arr[i][j]>maxlen) {
                            maxlen=arr[i][j];
                            startIndex=len-j-1;
                        }
                    }
                }
                return s.substring(startIndex,startIndex+maxlen);

    方法二动态规划:将填表的过程记录下来而不是从头来

    二维boolean[][]数组记录是某两位是不是回文串

    选取[l,r],s[l]==s[r]之间的字符串如果他是回文串,则[l+1,r-1]也是回文串

    //str[l,r] s[l]==s[r] 判断dp[l+1,r-1]是否为真
            if(s.isEmpty()) {
                return "";
            }
            int len=s.length();
            int strLen=1;
            int startIndex=0;
            
            boolean[][] dp=new boolean[len][len];
            
            for(int r=0;r<len;r++) {
                for(int l=0;l<r;l++) {
                    char left=s.charAt(l);
                    char right =s.charAt(r);
                    if(left==right&&((r-l<=2)||dp[l+1][r-1])) {
                        dp[l][r]=true;
                        if((r-l+1)>strLen) {
                            strLen=r-l+1;
                            startIndex=l;
                        }
                    }
                }
            }
            return s.substring(startIndex,startIndex+strLen);

     方法三:马拉车!!!神奇的马拉车算法!!!

    核心思路:求出每个i对应的p[i]->找到最大的p[i]->求出下标和长度,截取返回

    零、处理奇偶

    在字符串头+"^",尾加+"$"

    在每两个字符串之间+“#”

    偶数->+头尾(偶数)->+奇数个间隔->奇数

    奇数->+头尾(奇数)->+偶数个间隔->奇数

    一、求出P[i]

    中心扩展算法:从i开始向两边扩展比较,因为需要两个for循环所以空间复杂度约为O(n^2),为了减少中心扩展算法的时间复杂度,增加镜像法

    镜像法:

    C:回文串的中心

    R:回文串的右边界

    p[i]:i对应的回文串长度

    i_mirror:i关于C对应的镜像

    R>=i时,因为C是某个回文串的中心,二i又在此回文串右边界的左边,i可以用对应的i-mirror表示p[i]减少中心扩展算法的循环,使它变为某一常数即时间复杂度降为线性的了,注意当i+p[i_mirror]>R时,p[i_mirror]不一定是p[i],因为只有在R的范围里面它才是回文串,所以p[i]=min(R-i,i[i_mirror]),在这个的p[i]基础上再使用中心扩展算法时循环的就减少了

    C和R的更新:因为要尽量少的使用中心扩展算法,尽量多的使用镜像法,需要将R尽量变大,但是一个确定回文串对应的p[i]是一定的,即R是一定的,只有将右边i+p[i]更大的R更新才能达到目的,所以只要出现新的R大于当前C对应的R就要更新

    二 、找到最大下标和长度

    因为p[i]是#改变后的,所以在原字符串中maxlen=p[i]max,对应的下标为 (C对应的i - maxLen) / 2

    class Solution {
        public String longestPalindrome(String s) {
             String T = preProcess(s);
         int n = T.length();
         int[] P = new int[n];
         int C = 0, R = 0;
         for (int i = 1; i < n - 1; i++) {
             int i_mirror = 2 * C - i;
             if (R > =i) {
                 P[i] = Math.min(R - i, P[i_mirror]);
             } 
             // 中心扩展算法对p[i]的更新
             while (T.charAt(i + 1 + P[i]) == T.charAt(i - 1 - P[i])) {
                 P[i]++;
             }
             // 更新 C,R
             if (i +P[i] > R) {
                 C = i;
                 R = i + P[i];
             }
         }
         // 找出 P 的最大值
         int maxLen = 0;
         int centerIndex = 0;
         for (int i = 1; i < n - 1; i++) {
             if (P[i] > maxLen) {
                 maxLen = P[i];
                 centerIndex = i;
             }
         }
         int start = (centerIndex - maxLen) / 2; 
         return s.substring(start, start + maxLen);
        }
        public static String preProcess(String s) {
         int n = s.length();
         if (n == 0) {
             return "^$";
         }
         String ret = "^";
         for (int i = 0; i < n; i++)
             ret += "#" + s.charAt(i);
         ret += "#$";
         return ret;
     }
    }
  • 相关阅读:
    CF1324F Maximum White Subtree(树形dp)
    定时任务集群部署
    zookeeper服务的注册与发现
    多个定时任务服务注册到zookeeper临时顺序节点配置
    nginx反向代理
    nginx反向代理、负载均衡
    Eclipse快捷键
    下拉列表中复选框多选
    Zookeeper节点查看工具
    git打tag
  • 原文地址:https://www.cnblogs.com/code-fun/p/11437651.html
Copyright © 2011-2022 走看看