LeetCode:最长回文子串

题目:

LeetCode:最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

解题思路:

**way 一:**用求解 最长公共子序列 的方法 求解 字符串s的 最长回文子串,具体思路如下:
令字符串r = s[::-1]
求 s和r的最长公共子串,且要求 子串的索引 与 反向子串的原始索引 相同,满足条件 即为 一个 回文子串,更新 最长回文子串,否则,跳过该候选项,继续寻找下一个候选项。

提示:使用 矩阵 的方法,求解 最长公共子串,时间复杂度 为O(n2)。

代码如下:

class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        r = s[::-1] #转置字符串
        length = len(s)
        if(length<1):
            return ""
        
        #求解 r和s的最长公共子串,并且确定最长公共子串是否为 最长回文子串
        #利用矩阵的思想 求解 最长公共子串,如果s[i] = r[j],则loc[i,j]=1,如果s[i+1] = r[j+1],则loc[i+1,j+1] = loc[i,j]+1,否则,loc[i+1,j+1]=0
        import numpy as np
        layer= np.zeros((1,length))
        max = np.zeros((1,length))
        matrix = np.zeros((length,length))
        for i in range(length): #代表字符串s
            for j in range(length): #代表字符串r
                if((s[i]==r[j]) and (i==0 or j==0)):
                    matrix[i,j]=1
                
                elif(s[i]==r[j] and (i != 0 and j!= 0)):
                    matrix[i,j] = matrix[i-1,j-1] + 1
                
                if((matrix[i,j] > max[0,j]) and ((i+1-matrix[i,j])==(length-1-j))):
                    max[0,j] = matrix[i,j]
                    layer[0,j]=i            
                
            
        label=0
        MAX = 0
        #print(length)
        #得到的矩阵斜线即为最长 回文字符子串
        for j in range(length):
            if(max[0,j] > MAX):
                MAX = max[0,j]
                label = j
        
        #print(max[0,label])
        
        a = int(layer[0,label]-max[0,label]+1)   
        b = int(layer[0,label]+1)
        #print(a,b)   
        
        return s[a:b]

使用这种方法求解 最长回文子串,会超过时间限制,不可行。

way 二:暴力法
列举出 可能的 回文子串 的start_char和end_char,共为C(n,2)个,依次匹配字符串s,求解出 最长回文子串,该方法的时间复杂度达到了O(n3),较 way 一,更不可行。

way 三:动态规划法
核心思想为递归,但是与递归不同的是,减少一些重复计算的工作。我们可以保存较短 回文子串P[i,j]=true,在求解 P[i-1,j+1]时,只要求s[i-1] ?= s[j+1]即可,而不需要重新回溯 所有 字符。
true i=j //单字符的形式
P[i][j] = true j-1=1 //双字符的形式
P[i][j]=true && P[i-1][j+1] //扩展

代码如下:

class Solution {
    
    
    public String longestPalindrome(String s) {
    
    
        if(s.length() < 2){
    
    
            return s;
        }
        boolean [][] dp = new boolean[s.length()][s.length()];
        String result = s.substring(0,1);
        for(int j=0;j<s.length();++j){
    
    
            for(int i=0;i<=j;++i){
    
    
                dp[i][j] = s.charAt(i) == s.charAt(j) && (j-i<=2 || dp[i+1][j-1]); //这里有个疑问?如果i=j=length-1,那dp[i+1]不会越界吗?
                if(dp[i][j]){
    
    
                    if(j-i+1 > result.length()){
    
    
                        result = s.substring(i,j+1);
                    }
                }
                
                
            }
        }
        return result;
    }
}

动态规划算法的时间复杂度为O(n2),空间复杂度为O(n2);
思考:空间复杂度是否可以降为O(n)?

way 四:中心扩展法
遍历字符串s的每个元素,求以它为中心的 奇数/偶数 回文子串长度。设立Flag,记录Max 回文子串。
代码如下:

public String longestPalindrome(String s) {
    
    
    if (s == null || s.length() < 1) return "";
    int start = 0, end = 0;
    for (int i = 0; i < s.length(); 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;
}

中心扩展法 时间复杂度为O(n2),空间复杂度为O(1);

**way 五:Manacher算法:**求解 最长回文子串 的一个专用算法,其时间复杂度可以达到O(n),空间复杂度为O(1),具体参考博文:Manacher算法介绍

参考博文:
最长回文子串 (动态规划法、中心扩展算法)
LeetCode

猜你喜欢

转载自blog.csdn.net/u014765410/article/details/96724901