问题
a : abbaabbaaba
b : abbaaba
求字符串a中一共有几个b字符串
思路
- 复杂度(O n * m)常规的思路是从a的第一位开始和b进行比较,如果碰到一个字母不同,说明从a的第一个开始不能成功匹配。于是就从a的第二个字母与b相比较。
- 复杂度(O n * m)在方法一的基础上,发现一个字母不匹配的话,如果a不回到第二个开始的话,这样复杂的降了很多。
如果a不回退,b就要回退。而且b回退的越少越好。
就例子而言:
a : abbaabbaaba
b : abbaaba
(下标从0开始)
当匹配到最后一个字母发现不同(a[6] != b[6] 即 b != a),这时候让a[6]和b[2]开始匹配。完美!
问题是你怎么知道是b[2]呢?这涉及到字符串的前后缀问题,也就是求解next数组
求next数组
//不懂的可以 手动模拟 || 百度 || 记住
Next[0] = -1;
int i = 0, j = -1;
while (i < m) { //m 表示数组或字符串的长度
if(j == -1 || b[i] == b[j]) {
Next[++i] = ++j; //赋值
}else {
j = Next[j]; //回溯
}
}
KMP模板
int a[N], b[N], Next[N]; //从a数组里匹配b数组
void get_next(int m) { //求Next数组
Next[0] = -1;
int i = 0, j = -1;
while (i < m) {
if(j == -1 || b[i] == b[j]) {
Next[++i] = ++j; //赋值
}else {
j = Next[j]; //回溯
}
}
}
int kmp(int n, int m) {
get_next(m); //求Next数组
int i = 0, j = 0;
int ans = 0;
while (i < n) {
if (j == -1 || a[i] == b[j]) { //当前匹配成功进行下一个匹配
i++;
j++;
}else {
j = Next[j];
}
if (j == m) { //匹配成功
ans++;
j = Next[j]; //进行下一次匹配
}
}
return ans;
}