「Leetcode」Longest Palindromic Substring——最长回文子串

问题描述

Given a string S ,find the longest palindromic substringin S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.

什么是回文串

这种对称的,从前往后拼写和从后往前拼写一样的字符,分为奇数长度和偶数长度

“abba” “abcba” “abcddcba”

解决方案

1.暴力枚举

以每一个元素作为中间元素,同时从左右出发,复杂度为O(\(n^2\)),这里要考虑到奇数类型和偶数类型的回文串~

讲真,这种太慢了,AC后只打败了3%的人!

public class Solution {
    /**
     * @param s: input string
     * @return: the longest palindromic substring
     */
    public String longestPalindrome(String s) {
       // write your code here
        char[] S = s.toCharArray();
        int sLength = S.length;

        int maxLength = 1;
        String resultSbuString = "";

        for(int i=0;i<sLength;i++){

            int l = -1;
            int r = Integer.MAX_VALUE;

            //偶数型
            if(i + 1< sLength  && S[i] == S[i+1]) {

                int tempLength  = 0;
                String  tempSubStr = "";

                l = i - 1;
                r = i + 2;
                tempLength = 2;
                tempSubStr = s.substring(i,i+2);

                while(l >= 0 && r < sLength && S[l] == S[r]){
                    tempLength ++;
                    tempSubStr = s.substring(l,r+1 );

                    l--;
                    r++;
                }

                if(resultSbuString.length() < tempSubStr.length()){
                    maxLength = tempLength;
                    resultSbuString = tempSubStr;
                }
            }

            //奇数型
            if(i < sLength ){

                int tempLength  = 0;
                String  tempSubStr = "";

                l = i-1;
                r = i+1;
                tempLength  = 1;
                tempSubStr = s.substring(i,i+1);

                while(l >= 0 && r < sLength && S[l] == S[r]){
                    tempLength ++;
                    tempSubStr = s.substring(l,r+1 );

                    l--;
                    r++;
                }

                if(resultSbuString.length() < tempSubStr.length()){
                    maxLength = tempLength;
                    resultSbuString = tempSubStr;
                }
            }
        }
        return resultSbuString;
    }
}

2.记忆化搜索

我们使用 f[i][j] = “aba” 表示字符串S中下标从 i ~ j 的最长回文子串是 “aba”

  • 每次获取 f[i][j]的时候,先从二维数组中的记录中获取,如果没有那么再递归从他的子串中获取
  • 如果 i == j ,说明这时候求的是一个字符的最长回文子串,就是这个 S[i] 字符自身
  • 如果 i != j 的情况下,S[i] == S[j],并且 f[i+1][j-1] == S[i+1][j-1] ,那么 f[i][j] = S[i][j],
  • 如果 i != j ,而且S[i] != S[j],那么 f[i][j] 的来源有三个,f[i+1][j-1] , f[i+1][j], f[i][j-1], 取最大的即可

本质就是递归,是在递归的时候记录处理过的数据,这种方法的复杂度为O(\(n^2\)),AC后依然是只超过了3%的人,这就很难受。。。

public class Solution {
    /**
     * @param s: input string
     * @return: the longest palindromic substring
     */
    public String longestPalindrome(String s) {
       // write your code here
        char[] S = s.toCharArray();
        int sLength = S.length;
        String[][] f = new String[sLength ][sLength ];

        return generateLongestPalindromeSubString(f,0,sLength-1, s, S);
    }
    
    
     private String generateLongestPalindromeSubString(String[][] f,int i,int j,String s,char[] S){

        if(i<0 || j>=s.length() || i>j){
            f[i][j] = "";
            return f[i][j];
        }

        if(f[i][j] != null && !"".equals(f[i][j])){
            return f[i][j];
        }


        if(i==j){
            f[i][j] = s.substring(i,i+1);
            return f[i][j];
        }else if(S[i] == S[j] &&  s.substring(i+1,j).equals(generateLongestPalindromeSubString(f,i+1,j-1,s,S))){
            f[i][j] = s.substring(i,j+1);
            return f[i][j];
        }else {
            String s1 = generateLongestPalindromeSubString(f,i+1,j-1, s, S);
            String s2 = generateLongestPalindromeSubString(f,i,j-1, s, S);
            String s3 = generateLongestPalindromeSubString(f,i+1,j, s, S);

            String maxS = s1;
            if(maxS.length()<s2.length()){
                maxS = s2;
            }
            if(maxS.length() < s3.length()){
                maxS = s3;
            }

            f[i][j] = maxS;

            return f[i][j];
        }

    }


}

3.动态规划

我们使用 f[i][j] 表示在字符中 i-j 是否是回文子串

  • i == j ,f[i][j] = True
  • i+1 == j , f[i][j] = s[i] == s[j]
  • i+1 < j , f[i][j] = (s[i]==s[j] && f[i+1]f[j-1])

记忆搜索对比动态规划就像是俄罗斯套娃的两种操作,记忆搜索是在一层一层的揭开套娃,动态规划是从短到长,一层一层的套上去

public class Solution {
    /**
     * @param s: input string
     * @return: the longest palindromic substring
     */
    public String longestPalindrome(String s) {
       // write your code here
      char[] S = s.toCharArray();
        int sLength = S.length;

        boolean[][] f = new boolean[sLength][sLength];

        int maxLength = 1;
        int start = 0;
        for(int j=0;j<sLength;j++){

            for(int i=0;i<=j;i++){
                if(i==j){
                    f[i][j]=true;
                }else if(j == i+1){
                    f[i][j] = S[i] == S[j];
                }else if(j > i+1){
                    f[i][j] = (S[i]==S[j] && f[i+1][j-1]);
                }

                //
                if(f[i][j] && (j-i + 1 >maxLength )){
                    maxLength = j-i+1;
                    start = i;
                }
            }
        }
        return s.substring(start, start + maxLength);
    }

}

4.Manacher's Algorithm-马拉车算法

这篇博客写的很好了,想具体了解马拉车算法的可以移步这里 - Manacher's Algorithm-马拉车算法

public class Solution {
    /**
     * @param s: input string
     * @return: the longest palindromic substring
     */
    public String longestPalindrome(String s) {
       // write your code here
         char[] S = s.toCharArray();
        StringBuilder res = new StringBuilder("$#");
        for (int i=0;i<S.length;i++){
            res.append(S[i]).append("#");
        }

        S = res.toString().toCharArray();
        int[] p = new int[S.length];

        int mi = 0,right = 1;
        int maxPoint = 0,maxLength = 0;

        for(int i=1;i<S.length;i++){
            p[i] = i < right ? Math.min(p[2*mi-i],right-i) : 1;

            while(i+p[i] < S.length && S[i+p[i]] == S[i-p[i]]){
                p[i]++;
            }

            if(i+p[i] > right){
                mi = i;
                right = i+p[i];
            }

            if(p[i]>maxLength){
                maxPoint = i;
                maxLength = p[i];
            }
        }

        return s.substring((maxPoint-maxLength)/2, (maxPoint-maxLength)/2 + maxLength-1);
     
    }

}
posted @ 2020-04-13 14:54  用飘柔不秃头  阅读(127)  评论(0)    收藏  举报
这是一个测试连接