一、题目概要
来源:力扣(LeetCode)
链接:力扣
给你一个字符串 s
,找到 s
中最长的回文子串。
示例1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例2:
输入:s = "cbbd"
输出:"bb"
二、初始思路及代码
1、初始思路
使用类似第二题的滑动窗口解决->通过改变不同的启示位置依次尝试不同的字符串,与其逆转后的字符串对比,若二者相等则更新最大长度和最长回文,否则继续进行查找。
2、未通过的代码
class Solution {
public:
string longestPalindrome(string s) {
int maxLength=0;
string ans="";
for(int i=0;i<s.length();i++){
string tempStr="";
string str="";
for(int j=i;j<s.length();j++){
str+=s[j];
tempStr=str;
reverse(str.begin(),str.end());
if(tempStr==str){
if(str.length()>maxLength){
maxLength=str.length();
ans=tempStr;
}
}
str=tempStr;
}
}
return ans;
}
};
3、错误分析
通过双重循环+逆转判断等操作增大了时间复杂度,导致运行超时未能通过。
三、正确答案
1、动态规划
1.1思路
设P(i,j)为存放是s[i]~s[j]是否为回文的判断结果的bool型变量,则会出现一个规律:当s[i:j](从s[i]到s[j])为回文时,s[i+1:j-1]也必定是回文,根据此规律可发现该问题存在递推关系。
此时有两个特殊情况:
①当s[i:j]的长度为1时,则该字符串必定是回文
②当s[i:j]的长度为2时,只要满足s[i]==s[i+1]则该字符串必定为回文
因此可以用情况②作为递推的底层,进而判断出所需结果。
1.2代码
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();
if(n<2){
return s;
}
int maxLen=1,begin=0;
vector<vector<int>>dp(n,vector<int>(n));//用dp[i,j]存放从i到j的字符串是否为回文的判断结果
for(int i=0;i<n;i++){
dp[i][i]=true;
}
//枚举可能的回文长度
for(int len=2;len<=n;len++){
for(int i=0;i<n;i++){//左边界
int j=len+i-1;//右边界
if(j>=n){
break;//右边界越界
}
if(s[i]!=s[j]){
dp[i][j]=false;
}
else{
if(j-i<3){
dp[i][j]=true;
}
else{
dp[i][j]=dp[i+1][j-1];//递推
}
}
if(dp[i][j]&&j-i+1>maxLen){
maxLen=j-i+1;
begin=i;
}
}
}
return s.substr(begin,maxLen);
}
};
1.3代码分析
时间复杂度O(n^2)
空间复杂度O(n^2)
2中心扩展算法
2.1思路
核心思想与递推类似,依次选定字符串不同位置的s[i]作为中心点,依次向外扩展。根据上一解法可知,如果s[i:j]是回文,则s[i+1:j-1]必然是回文。因此该算法利用该特点向外扩展,直到扩展到的两个字符s[i]和s[j]不再相等后,返回两个下标i和j。
此外,扩展是会遇到两个不同情况:
①以奇数字符为中心,如bab的中心字符为a,是奇数字符,此时只需要从下标为1的位置直接向外扩展即可
②以偶数字符为中心,如baab的中心字符为aa,是偶数字符,此时则需要从i和i+1两个位置分别向外扩展
因此在书写外接函数时直接确定两个下标变量,若是情况①则传入i和i,若是情况②则传入i和i+1。
2.2代码
class Solution {
public:
pair<int,int>expandAroundCenter(const string& s,int left,int right){
while(left>=0&&right<s.size()&&s[left]==s[right]){
//向外扩展->感觉类似递推
left--;
right++;
}
return {left+1,right-1};
}
string longestPalindrome(string s) {
int begin=0,end=0;
for(int i=0;i<s.size();i++){
auto [left1,right1]=expandAroundCenter(s,i,i);//长度为1的情况
auto [left2,right2]=expandAroundCenter(s,i,i+1);//长度为2的情况
if(right1-left1>end-begin){
begin=left1;
end=right1;
}
if(right2-left2>end-begin){
begin=left2;
end=right2;
}
}
return s.substr(begin,end-begin+1);
}
};
2.3代码分析
时间复杂度:O(n^2)
空间复杂度:O(1)
3、Manacher 算法(等后期有兴趣再补充)
四、每日打卡(滴滴!!)
2022.4.15 打卡完成!!!