回文子串
第一个想法就是暴力解题,遍历所有子串,找出最大的,毫无疑问,双重循环很耗时:
class Solution:
def longestPalindrome(self, s: str) -> str:
data = []
maxstring = []
for i in range(len(s)):
for j in range(i+1,len(s)+1):
data = s[i:j]
if data == data[::-1]:
if len(data) > len(maxstring):
maxstring = data
return maxstring
改进,减少循环次数,7248 ms,15mb:
class Solution:
def longestPalindrome(self, s: str) -> str:
max_s = 0
m_s = []
for i in range(len(s)):
for j in range(len(s)):
if j>i and s[i]==s[j]:
if s[i:j+1] == s[i:j+1][::-1]:
if j-i+1 > max_s:
max_s = j - i + 1
m_s = s[i:j+1]
if not m_s:
m_s = s[0]
return m_s
第二个方法就是动态规划法,牺牲空间来换时间
class Solution {
public:
string longestPalindrome(string s) {
string ans=s.substr(0,1);
int maxLen=1;
auto len=s.size();
vector<vector<bool>> dp(len,vector<bool>(len,0));
for(int i=0;i!=len;++i)dp[i][i]=1;//初始化边界条件,即对角线
//第一层遍历边界,设置子字符串范围,范围为0-j
for(int j=1;j!=len;++j){
//第二层遍历遍历子字符串内部。即0到j区间内的所有字符串,可理解为孙字符串
for(int i=0;i!=j;++i){
if(s[i]!=s[j])dp[i][j]=0;//如果子字符串边界不相等,那么这个子字符串必然不是回文
//字符串边界相等的情况下,其长度小于等于3的情况,那么必然是回文。如aba,bb。这个点也是最难想到的
else if(j-i<3)dp[i][j]=1;
//字符串边界相等的情况下,其是否为回文取决于i+1到j-1范围内的字符串是否为回文
else dp[i][j]=dp[i+1][j-1];
//如果当前字符串的长度比之前的最大长度还长,那么覆盖
if(dp[i][j]&&maxLen<j-i+1)maxLen=j-i+1,ans=s.substr(i,maxLen);
}
}
return ans;
}
};
第三个方法就是中心扩散法,要注意一点,中心是一个字母还是两个字母
class Solution {
public:
string longestPalindrome(string s) {
int maxLen=1;
string ans=s.substr(0,1);
//中心扩散法,遍历字符串s,判断每个位置可构成的最大回文串
for(int i=0;i<s.size()-1;++i){
int start=i,end=i;
//情况1:中心只有一个字母的情况。如aba
for(int l=i-1,r=i+1;l!=-1&&r!=s.size();--l,++r){
if(s[l]==s[r]){start=l;end=r;}//如果一直符合回文要求,继续往两边扩散
else break;//一不符合要求马上终止
}
//如果当前字符串的长度比之前的最大长度还长,那么覆盖
if(end-start+1>maxLen)maxLen=end-start+1,ans=s.substr(start,maxLen);
//情况2:中心只有两个字母的情况。如abba
if(i!=s.size()-1&&s[i]==s[i+1]){
for(int l=i,r=i+1;l!=-1&&r!=s.size();--l,++r){
if(s[l]==s[r]){start=l;end=r;}//如果一直符合回文要求,继续往两边扩散
else break;//一不符合要求马上终止
}
}
//如果当前字符串的长度比之前的最大长度还长,那么覆盖
if(end-start+1>maxLen)maxLen=end-start+1,ans=s.substr(start,maxLen);
}
return ans;
}
};