KMP算法
next数组含义
表示i之前的字符串前后缀相等的最大长度
主函数与回跳过程图
int getIndexof(string& s1,string& s2) {
if (s1.empty() || s2.empty())
return -1;
int i1 = 0; int i2 = 0;
vector<int>next = getNextArray(s2);
while (i1 < s1.size() && i2 < s2.size()) {
if (s1[i1] == s2[i2]) {
i1++;
i2++;
}
else if (i2 == 0) //str2比对的位置已经无法往前跳了
i1++;
else
i2 = next[i2];
}
//i1或者i2越界
return i2 == s2.size() ? i1 - i2 : -1;
}
next数组建立方法
cn的含义:前缀的下一个字符的位置 和i-1位置比
现在使用的信息长度是多少
next[i++] = ++cn的意思:next[i++]=cnt+1 cnt++
cnt++是为什么:当来到下一个位置i+1时 需要用到的是cnt+1的值
vector<int> getNextArray(string& ms) {
if (ms.size()==1) {
return { -1 };
}
vector<int>next(ms.size());
next[0] = -1; next[1] = 0;;
int i = 2; //next数组位置
int cn = 0;
while (i < next.size()) {
if (ms[i - 1] == ms[cn])
next[i++] = ++cn;
//当前跳到cn位置和i-1位置匹配不上
else if (cn > 0) //如果不等 cn>0 cn又可以往前跳
cn = next[cn];
else
next[i++] = 0;
}
return next;
}
manacher算法
step1: 将字符之间都加上特殊符号 记作“#”
step2:扩散三种情况
三种情况
1.当前位置不在回文最右边界 暴力括
2.当前位置在回文边界里
2情况根据i'状况 继续可以分类
(1)i'在L,R内部
结论:i的回文半径与i'相等
(2)i'部分在L,R外部
结论:i的回文半径是R-i
3.压线
结论:i的回文半径至少是 R-i
是否更远需要验证
代码
伪代码
代码
string manacherString(string str) {
string res;
int index = 0;
for (int i = 0; i != res.size(); i++) {
res[i] = (i & 1) == 0 ? '#' : res[index++];
}
return res;
}
int maxLcpsLength(string s) {
if (s.empty())
return 0;
vector<int>arr(s.size());
int c = -1; //中心
int R = -1; //回文右边界再往右的一个位置 最右有效位置是R-1
int Max = INT_MIN; //扩出来的最大值
for (int i = 0; i != s.size(); i++) {
//i至少的回文区域 先给pArr
arr[i] = R > i ? min(arr[2 * c - i], R - i) : 1;
while (i + arr[i] < s.size()&&i-arr[i]>-1) {
if (s[i + arr[i]] == s[i])
arr[i]++;
else
break;
}
if (i + arr[i] > R) {
R = i + arr[i];
c = i;
}
Max = max(Max, arr[i]);
}
return Max - 1;
}