【leetcode 5. 最长回文子串】解题报告
方法一:中心扩展算法
解题思路:从左到右每一个字符都作为中心轴,然后逐渐往两边扩展,只要发现有不相等的字符,则确定了以该字符为轴的最长回文串,但需要考虑长度为奇数和偶数的不同情况的处理(长度为偶数时轴心为中间两个数的中心,长度为奇数时轴心为中间那个数)
算法时间复杂度:$O(n^{2})$
string longestPalindrome(string s) { int idx = 0, maxL = 0; for (int i = 0; i < s.size(); ++i) // i为轴的位置,j为回文串半径 { for (int j = 0; i - j >= 0 && i + j < s.size(); ++j) // 奇数 { if (s[i - j] != s[i + j]) break; if (2 * j + 1 > maxL) { maxL = 2 * j + 1; idx = i - j; } } for (int j = 0; i - j >= 0 && i + j + 1 < s.size(); ++j) // 偶数 { if (s[i-j]!=s[i+j+1]) break; if (2 * j + 2 > maxL) { maxL = 2 * j + 2; idx = i - j; } } } return s.substr(idx, maxL); }
方法二:manacher(马拉车法)
解题思路:详见P3805 【模板】manacher算法
算法时间复杂度为:$O(n)$
int pos[2005],p[2005]; string longestPalindrome(string s) { /* 填充字符,统一为奇数串 */ string s_new="~"; for (int i=0,k=1;i<s.size();++i) { s_new+="#"; s_new+=s[i]; pos[k++]=i; // 记录新字串与原始字串的位置关系 pos[k++]=i; } s_new+="#"; /* manacher */ int m=0,r=0,maxL=0,idx=0; for (int i=1;i<s_new.size();++i) { // 获取已知的最小回文半径 if (i<r) p[i]=min(p[2*m-i],r-i); else p[i]=1; // 暴力拓展左右两侧 while (s_new[i-p[i]]==s_new[i+p[i]]) p[i]++; // 新的回文半径比较大,则更新 if (r-i<p[i]) { m=i; r=i+p[i]; } // 更新回文长度(原始字串的回文长度为新字串回文半径-1) if (p[i]-1>maxL) { maxL=p[i]-1; idx=pos[i]-maxL/2; // 更新原始回文字串的起始位置 } } return s.substr(idx,maxL); }