1.动态规划算法:
之所以逆序遍历是因为避免重复计算:在动态规划中,我们通常希望先计算子问题的解,然后再用这些解来构建更大问题的解。通过从字符串的末尾开始向前遍历,我们可以确保在计算任意子串 s[i…j] 是否为回文之前,子串 s[i+1…j-1] 已经被计算过了。这样可以避免重复计算,并且确保每个子串只被计算一次。
a数组含义:
a
[
i
]
[
j
]
=
t
r
u
e
,表示从下标
i
到下标
j
,字符
s
[
i
]
→
s
[
j
]
是回文子串!
a[i][j] = true,表示从下标i到下标j,字符s[i] \to s[j]是回文子串!
a[i][j]=true,表示从下标i到下标j,字符s[i]→s[j]是回文子串!
时间复杂度:
O
(
n
2
)
时间复杂度:O(n^2)
时间复杂度:O(n2)
空间复杂度:
S
(
n
2
)
空间复杂度:S(n^2)
空间复杂度:S(n2)
class Solution{
public:
string longestPalindrome(string s){
#define N 1010
string res = s.substr(0,1);
int a[N][N];
for(int i=s.size()-1;i>=0;i--){
for(int j=i+1;j<s.size();j++){
if(i == j){
a[i][j] = true;//这个if语句其实可以直接删除优化掉的!
}
else if(j - i <= 2){
a[i][j] = s[i]==s[j];
}
else{
a[i][j] = a[i+1][j-1] && s[i]==s[j];
}
if(a[i][j] && j-i+1 > res.size()){//如果i到j这个子串是回文串,并且优于目前最优解,截取记录最长回文子串!
res = s.substr(i,j-i+1);
}
}
}
return res;
}
};
2.中心扩展:
代码十分简洁,摆手无需多言
时间复杂度:
O
(
n
2
)
时间复杂度:O(n^2)
时间复杂度:O(n2)
空间复杂度:
S
(
1
)
空间复杂度:S(1)
空间复杂度:S(1)
class Solution{
public:
string res;
string longestPalindrome(string s){
res = s.substr(0,1);//O(1)复杂度
for(int i = 0 ; i < s.size(); ++ i){
extend(s,i,i);//以i为中心扩展回文子串,奇数长度
extend(s,i,i + 1);//尝试找到以 i 和 i+1 为中心的最长回文子串(偶数长度)。
}
return res;
}
void extend(string& str,int l,int r){
while(l >= 0 && r < str.size() && str[l] == str[r])
l -- , r ++;
if(r - l - 1 > res.size())
res = str.substr(l + 1 , r - l - 1);
}
};
参考链接:
【史上最燃算法刷题!Leetcode 5. 最长回文子串】 https://www.bilibili.com/video/BV1dN4y1g7p9/?share_source=copy_web&vd_source=afbacdc02063c57e7a2ef256a4db9d2a