题目描述
解法1:动态规划
1.定义dp数组
定义一个bool型dp二维数组dp[i][j],i表示开始位置,j表示结束位置,true表示是回文子串
2.初始状态
dp[i][i]=1; //单个字符是回文串
dp[i][i+1]=1 if s[i]=s[i+1]; //连续两个相同字符是回文串
3.状态转移方程
dp[i][j]=dp[i+1][j-1]
&& $s_i==s_j$
4.初始化一字母和二字母回文,然后找到所有三字母,以此类推
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Solution { public: string longestPalindrome(string s) { int n=s.length(); if(n<=1) return s; vector<vector<int>> bp(n,vector<int>(n)); int l; int length=1; int start=0; int i; for(i=0;i<n;i++) { bp[i][i]=1; if((i<n-1)&&s[i]==s[i+1]) { bp[i][i+1]=1; length=2; start=i; } } for(l=3;l<=n;l++) { for(i=0;i+l-1<n;i++) { int j=i+l-1; if(s[i]==s[j]&&(bp[i+1][j-1]==1)) { bp[i][j]=1; length=l; start=i; } } } return s.substr(start,length); } };
|
复杂度分析
- 时间复杂度($n^2$)
- 空间复杂度($n^2$)
解法2:中心扩展算法
事实上,只需使用恒定的空间,我们就可以在 O($n^2$) 的时间内解决这个问题。
我们知道回文串一定是对称的,所以我们可以每次循环选择一个中心,进行左右扩展,判断左右字符是否相等即可。
由于存在奇数的字符串和偶数的字符串,所以我们需要从一个字符开始扩展,或者从两个字符之间开始扩展,所以总共有 n + n - 1 个中心。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class Solution { public: string longestPalindrome(string s) { int n=s.length(); if(n<=1) return s; int start=0; int i; int length=1; for(i=0;i<s.length();i++) { int len1=expandAroundCenter(s,i,i); int len2=expandAroundCenter(s,i,i+1); int len=max(len1,len2); if(len>length) { start=i-(len-1)/2; length=len; } } return s.substr(start,length); } int expandAroundCenter(string s,int left,int right) { int l=left,r=right; while(l>=0&&r<s.length()&&s[l]==s[r]) { l--; r++; } return r-l-1; } };
|
复杂度分析
解法3.Manacher’s Algorithm 马拉车算法
马拉车算法 Manacher‘s Algorithm 是用来查找一个字符串的最长回文子串的线性方法,由一个叫Manacher的人在1975年发明的,这个方法的最大贡献是在于将时间复杂度提升到了线性。
参考下边链接。
https://segmentfault.com/a/1190000008484167
https://blog.crimx.com/2017/07/06/manachers-algorithm/
http://ju.outofmemory.cn/entry/130005
https://articles.leetcode.com/longest-palindromic-substring-part-ii/
https://leetcode.wang/leetCode-5-Longest-Palindromic-Substring.html