题目:
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算法介绍