最长回文子串(动规,中心扩散法,Manacher算法)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

最长回⽂⼦串(动规,中⼼扩散法,Manacher算法)题⽬
解法
动态规划
时间复杂度O(n2),空间复杂度O(n2)
基本解法直接看代码
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
vector<vector<bool>> dp(n, vector<bool>(n, true));
int rx, ry;
rx = ry = 0;
for(int l = 1; l < n; l++){
for(int i = 0; i < n - l; i++){
int j = i + l;
if(s[i] == s[j] && (j - i < 3 || dp[i+1][j-1])){
dp[i][j] = true;
if(j - i > ry - rx){
ry = j;
rx = i;
}
} else {
dp[i][j] = false;
}
}
}
return s.substr(rx, ry - rx + 1);
}
};
中⼼扩散法
时间复杂度O(n2),空间复杂度O(1)
我们先假定以某点为中⼼向两端扩散,找到以该点为中⼼的最长回⽂⼦串
class Solution {
public:
int rx, ry;
void helper(string &s, int i, int offset){
int left = i;
int right = i + offset;
while(left >= 0 && right < s.size() && s[left] == s[right]){
left--;
right++;
}
if(right - 1 - (left + 1) > ry - rx){
ry = right - 1;
rx = left + 1;
}
}
string longestPalindrome(string s) {
int n = s.size();
rx = ry = 0;
for(int i = 0; i < n; i++){
helper(s, i, 0);
helper(s, i, 1);
}
return s.substr(rx, ry - rx + 1);
}
};
Manacher算法
Manacher算法俗称“马拉车算法”,时间复杂度O(n),空间复杂度O(n)
因为回⽂字符串都有奇数长度的串和偶数长度的串,为了更好处理这两种情况,可以在字符串中插⼊⼀特殊字符'#',使得新字符串长度全变为奇数长度,如"aa"变为"#a#a#",可以再字符串⾸部加⼊另⼀特殊字符'$'和尾部的'@',这样就不⽤特殊处理越界问题(统⼀边界处理)以"122112321"为例经过上⼀步变成"@#1#2#2#1#1#2#3#2#1#"
Manacher算法使⽤⼀个辅助数组r[i]表⽰以t[i]为中⼼的最长回⽂⼦串的最右字符到t[i]的长度,如以t[i]为中⼼的最长回⽂⼦串为t[low, high],则r[i] = high - i + 1, t[low, high] = 2 * r[i]-1, len数组有⼀个性质,就是r[i]-1为该回⽂⼦串在原串中的长度,证明很简单t[lowl, high]⼀定是以"#"开头和结尾的,这样插⼊的"#"是原来串中字符的两倍还多⼀个,这样原串中最长回⽂串的长度就为r[i]-1,这样问题就转为求最长的r[i]
计算len数组
算法主要利⽤了已有的回⽂⼦串的特点,减少了查找时间,从左往右计算len[i],同时保存⼀个之前计算最长回⽂⼦串的右端点的最⼤值R及对应的中⼼位置c,
i < R, 则先找i关于c对称点j=2*c-i,则⾄少r[i] ≥ min(R - i + 1, p[j]), 超出部分再⼿⼯匹配
i >= R, 则不能利⽤以后的知识做任何假设,只能假定其⾄少为1,再⼿⼯匹配
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
if(n == 0) return "";
string ns;
ns.push_back('$');
for(int i = 0; i < n; i++){
ns.push_back('#');
ns.push_back(s[i]);
}
ns.push_back('#');
ns.push_back('@');
n = ns.size();
vector<int> r(n);
int c, R, C, MAX;
R = -1;
MAX = 0;
C = 0;
for(int i = 1; i < n; i++){
r[i] = i < R ? min(r[2 * c - i], R - i + 1) : 1;
while(ns[i + r[i]] == ns[i - r[i]]) r[i]++;
r[i]--;
if(i + r[i] > R){
R = i + r[i];
c = i;
}
if(r[i] > MAX){
MAX = r[i];
C = i;
}
}
return s.substr((C-MAX)/2, r[C]);
}
};
时间复杂度分析
参考。

相关文档
最新文档