LeetCode 5 最长回文子串 Manacher算法
2016-06-21 00:25
302 查看
题意
求最长回文子串思路
最长回文子串,我一直没好好学一下O(n)的算法,趁刷LeetCode的机会学一下~Manacher算法,其实还是一种dp的方法,这里大体介绍一下思路~
首先,一个小技巧,每隔一个字符插入一个’#’,如abc,变为#a#b#c#,这样就保证字符串一定奇数长,避免了奇偶处理的不同
第二,加入辅助数组p,p[i]表示以第i个字符为中心,最长的回文子串的半径。如#a#a#,p = {1,2,3,2,1},不难想象,p[i]-1,就是以第i个字符为中心,在原字符串中的最长回文子串的长度。
第三,核心问题就是p的更新。我们从前往后更新p[i]。问题是在已知p[0~i-1]时,如何快速递推求出p[i]。在迭代更新数组的过程中,我们维护两个变量mx 和 mxid。mx表示0~i-1中的回文子串里,右边界最远的位置,mxid则是该回文子串的中心位置。
根据回文的性质,当mx大于i时,我们有p[i] = min(p[2mxid-i], mx - i + 1),其中j = 2mxid-i表示i关于mxid的对称点,由于j在i的左侧,p[j]已经算出,又由于回文对称性,可以得到上式。具体理解可能需要画图会比较清晰~这里不再细说了~
第四,在实现过程中,可以在开头和结尾插入两个不同的,且没在序列中出现的字符,以保证匹配时不越界。
这里给出了O(n^2)和O(n)的两个实现。
实现
O(n^2)class Solution { public: int a[1005][1005]; string longestPalindrome(string s) { int n = s.length(); for (int i=0;i<n;i++){ a[i][i] = 1; } int ans = 1; pair<int,int> p; for (int len=1;len<n;len++){ for (int i=0;i+len<n;i++){ int j = i + len; if (s[i] == s[j]){ if (len == 1 || a[i+1][j-1] == 1){ a[i][j] = 1; if (len + 1 > ans){ ans = len+1; p = make_pair(i,j); } } } } } return s.substr(p.first, ans); } };
O(n)
class Solution { public: int p[3000]; string longestPalindrome(string s) { string s1; s1 += '&'; for (int i = 0; i<s.length();i++){ s1 += '#'; s1 += s[i]; } s1 += '#'; s1 += '@'; int n = s1.length()-1; int mx = 0, mx_id = 0; int ans = 0; int ansid = 0; for (int i=1;i<n;i++){ if (mx > i){ p[i] = min(p[2*mx_id-i], mx - i + 1); }else{ p[i] = 1; } while (s1[i-p[i]] == s1[i+p[i]]){ p[i]++; } if (i + p[i] - 1 > mx){ mx = i + p[i] - 1; mx_id = i; } if (p[i] > ans){ ans = p[i]; ansid = i; } } return s.substr((ansid-ans) / 2 , ans-1); } };
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法