- 蛮力算法
- KMP算法
蛮力算法
function indexof(text, pattern) {
if (text == null || pattern == null) return;
let tlen = text.length;
let plen = pattern.length;
if (tlen === 0 || plen === 0 || tlen < plen) return -1;
let pi = 0, ti = 0;
while(pi < plen && ti < tlen) {
if (text.charAt(ti) === pattern.charAt(pi)) {
ti++;
pi++;
} else {
ti -= pi - 1; // 下一轮开始比较的位置
pi = 0;
}
}
return pi == plen ? ti - pi : -1;
}
蛮力优化一: 在恰当的时候可以提前提出,较少比较次数
function indexof(text, pattern) {
if (text == null || pattern == null) return;
let tlen = text.length;
let plen = pattern.length;
if (tlen === 0 || plen === 0 || tlen < plen) return -1;
let pi = 0, ti = 0;
let tmax = tlen - plen;
// 只有text剩下可比较的长度大于pattern的长度才比较,否则无意义,一定是不包含的.
while(pi < plen && ti - pi <= tmax) {
if (text.charAt(ti) === pattern.charAt(pi)) {
ti++;
pi++;
} else {
ti -= pi - 1;
pi = 0;
}
}
return pi == plen ? ti - pi : -1;
}
蛮力算法实现2
function indexof(text, pattern) {
if (text == null || pattern == null) return -1;
let tlen = text.length;
let plen = pattern.length;
if (tlen === 0 || plen === 0 || tlen < plen) return -1;
let tmax = tlen - plen;
for (let ti = 0; ti <= tmax; ti++) {
let pi = 0;
for (;pi < plen; pi++) {
if (text.charAt(ti + pi) !== pattern.charAt(pi)) break;
}
if (pi === plen) return ti;
}
return -1;
}
蛮力算法性能分析
文本串长度 m 模式串长度
最好情况 只需一轮比较就完全匹配。比较m次,时间复杂度为o(m)
最坏情况,执行了 n - m + 1 轮比较,每轮比较到模式串的末字符串后失败(m -1)次成功,1次失败
时间复杂度为 o(m * (n - m + 1)) ----- o(mn)
Kmp
KMP 算法充分利用了此前比较过的内容,可以很聪明的跳过一些不必要的比较位置
function nextFn(pattern) {
let len = pattern.length;
// let next = new Array(len).fill(0);
let next = new Array(len);
let i = 0;
let n = next[i] = -1;
let imax = len - 1;
while(i < imax) {
if (n < 0 || pattern.charAt(i) == pattern.charAt(n)) {
next[++i] = ++n;
} else {
n = next[n];
}
}
return next
}
function indexof(text, pattern) {
if (text == null || pattern == null) return -1;
let tlen = text.length;
let plen = pattern.length;
if (tlen === 0 || plen === 0 || tlen < plen) return -1;
let next = nextFn(pattern);
let pi = 0, ti = 0;
let tmax = tlen - plen;
while(pi < plen && ti - pi <= tmax) {
if (pi < 0 || text.charAt(ti) === pattern.charAt(pi)) {
ti++;
pi++;
} else {
pi = next[pi];
}
}
return pi === plen ? ti - pi : -1;
}
KMP 主逻辑
最好时间的复杂度: O(m)
最坏时间复杂度: o(n), 不超过0(2n)
next 表的构造程度和KMP主体逻辑类似
时间复杂度: O(m)
KMP 整体
最好时间复杂度: O(m)
最坏复杂度: o(n+m)
空间复杂度: o(m)
蛮力算法 与 KMP 比较
当字符失配时
蛮力算法
ti 回溯到左边位置
pi 回溯到 0
KMP 算法
ti 不必回溯
pi 不一定回溯到0