没动态规划出来,就做不出来……
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();
if(n<2) return s;
int dp[n][n],pos=0,len=1;
memset(dp,0,sizeof(dp));
for(int i=1;i<n;++i)
{
dp[i][i]=1;
dp[i][i-1]=1;
}
dp[0][0]=1;
for(int i=n-2;i>=0;--i)
{
for(int j=n-1;j>i;--j)
if(s[i]==s[j]){
dp[i][j]=dp[i+1][j-1];
if(dp[i][j]&&(j-i)>(len-1))
{
pos=i;len=j-i+1;}
}
}
return s.substr(pos,len);
}
};
这种做法dp数组的i和j分别代表回文串两端的序号。官方解法则是从字符串长度和首序号出发。区别在于i、j如果是两段的序号的话,空间复杂度可以优化到O(N)。
实际上一开始我的做法是,先反转字符串,但是这种思路没做出来
再然后我想的是一遍遍历得出结果,异想天开了,思路是从头到尾分奇数回文串和偶数回文串分别进行验证
看了答案才知道以上两种都是可以做出来的。比较原字符串和反转字符串的话,相当于求最长公共子串,而我还陷在最长公共子序列里面,自然得不出来。
分别求奇数和偶数串则是陷入到一遍遍历里面,前面的结果会干扰到后面的结果的,正确就是按中心扩展法分别遍历奇数和偶数中心
最长公共子串解法
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();
if(n<2) return s;
string rev(s);
reverse(rev.begin(),rev.end());
int dp[n][n];
memset(dp,0,sizeof(dp));
int pos=0,len=1;
for(int i=0;i<n;++i)
{
for(int j=0;j<n;++j)
{
if(s[i]==rev[j]){
if(i==0||j==0)
dp[i][j]=1;
else
dp[i][j]=dp[i-1][j-1]+1;
int t_len=dp[i][j];
if(t_len>len&&j==(n-i-2+t_len))
{
len=t_len;pos=i-len+1;}
}
}
}
return s.substr(pos,len);
}
};
中心扩展法解法
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();
if(n<2) return s;
int pos=0,len=1;
for(int i=0;i<n;++i)
for(int j=i;j<i+2&&j<n;++j){
int t_len=maxstr(s,i,j);
if(t_len>len)
{
len=t_len;pos=j-len/2;}
}
return s.substr(pos,len);
}
int maxstr(string& s,int i,int j)
{
int res=0,n=s.size();
while(i>=0&&j<n&&s[i]==s[j])
{
--i;++j;}
return j-i-1;
}
};
而如果解决了回文串的奇偶性,那么就不用分奇偶了,然而还是O(N^2),但马拉车算法可以通过优化达到(N),但也只有天才才能想出来了