题目描述:给定一个字符串,找出字符串中最长的回文串。
eg:
-
input:abbc
-
output:bb
-
input:babad
-
output:bab or aba
我的代码(暴力法)
string longestPalindrome(string s)
{
map<int,string> vec;
if(s.size()==1) return s;
if(s.size()==2)
if(s[0]==s[1])
return s;
int length=s.size();
vec.insert({1,s.substr(0,1)});
while(length>1) //控制length长度
{
int i=0;
int mid=length/2;
int j=length-1;
while(i<=s.size()-length) //在length长度内迭代求解
{
int num=0;
int i_cp=i;
int j_cp=j;
int mid_cp=mid;
while(i_cp<mid_cp)
{
if(s[i_cp]==s[j_cp])
num++;
i_cp++;
j_cp--;
}
if(num==length/2)
{
vec.insert({length,s.substr(i,length)});
return s.substr(i,length);
}
else
i++,mid++,j++;
}
length--;
}
return vec[1];
}
复杂度分析:三个while循环的嵌套,所以O(n^3)级别
缺陷:复杂度高,虽然没什么问题,提交时系统给的输入是"klvxwqyzugrdoaccdafdfrvxiowkcuedfhoixzipxrkzbvpusslsgfjocvidnpsnkqdfnnzzawzsslwnvvjyoignsfbxkgrokzyusxikxumrxlzzrnbtrixxfioormoyyejashrowjqqzifacecvoruwkuessttlexvdptuvodoavsjaepvrfvbdhumtuvxufzzyowiswokioyjtzzmevttheeyjqcldllxvjraeyflthntsmipaoyjixygbtbvbnnrmlwwkeikhnnmlfspjgmcxwbjyhomfjdcnogqjviggklplpznfwjydkxzjkoskvqvnxfzdrsmooyciwulvtlmvnjbbmffureoilszlonibbcwfsjzguxqrjwypwrskhrttvnqoqisdfuifqnabzbvyzgbxfvmcomneykfmycevnrcsyqclamfxskmsxreptpxqxqidvjbuduktnwwoztvkuebfdigmjqfuolqzvjincchlmbrxpqgguwuyhrdtwqkdlqidlxzqktgzktihvlwsbysjeykiwokyqaskjjngovbagspyspeghutyoeahhgynzsyaszlirmlekpboywqdliumihwnsnwjc"(…),这样运行的时间太长,提交错误,需要别的算法。
Solution:
expendAroundcenter
算法思想:每个回文串都是关于某个元素对称的,所以我们可以从对称中心向左右拓展,偶数的对称中心是相邻且相等的两项
代码:
string longestPalindrome(string s)
{
int start=0;
int end=0;
for(int i=0;i<s.size();i++)
{
int len1=expendAroundcenter(s,i,i);
int len2=expendAroundcenter(s,i,i+1);
int len=max(len1,len2);
if(len>end-start+1)
{
start=i-(len-1)/2;
end=i+(len/2);
}
}
return s.substr(start,end-start+1);
}
int expendAroundcenter(string s,int left,int right)
{
int L=left;
int R=right;
while(L>=0&&R<s.size()&&(s[L]==s[R]))
{
L--;
R++;
}
return R-L-1;
}
复杂度:O(n^2)
Dynamic Programming:看作动态规划问题,我们维护一个二维数组dp[i][j],若dp[i][j]=1,则说明下标从i到j的子串为回文串,若dp[i][j]为回文串,那么dp[i+1][j-1]也必定为回文串
代码:
string longestPalindrome(string s)
{
if(s.size()==0)
return "";
int start=0;
int length=1;
int dp[s.size()][s.size()]={0};
for(int right=0;right<s.size();right++)
{
dp[right][right]=1;
for(int left=0;left<right;left++)
{
if(s[left]==s[right]&&(right-left<2||dp[left+1][right-1]==1))
{
dp[left][right]=1;
}
else
dp[left][right]=0; //不为1的,设为0,若不设置会乱码
if(dp[left][right]==1&&length<right-left+1)
{
start=left;
length=right-left+1;
}
}
}
return s.substr(start,length);
}
复杂度:O(n^2)
总结:
- 暴力算法虽然简单,但复杂度高,有时不适用(超过n^2时)
- 找出回文串的特点(对称)
- 动态规划时,要保证可变数组的长度为正值,因此先要判断空串的情况
- 因为没有考虑到数组元素不为1时的情况,因此在debug时花费了不少时间