穷举法
/*
Implement strStr().
Returns a pointer to the first occurrence of needle in haystack, or null if needle is not part of haystack
要求找到子字符串在字符串中第一次出现的位置。
相当于JS的indexOf函数
分析:
*/
// 穷举法
const strStr = function (haystack, needle) {
if (needle.length === 0) {
return 0;
}
const m = haystack.length;
const n = needle.length;
if (m < n) {
return -1;
}
// i是 haystack跟needle比较的位置
// (m - n)是 剩余可比较的位置
for (let i = 0; i <= m - n; i++) {
// j是 needle参数 里面字符的比较位置
for (let j = 0; j < n; j++) {
// 有一个未匹配则进行haystac的下一轮比较
if (haystack[i + j] !== needle[j]) {
break;
}
/*
n是 needle参数的长度,j是needle比较位置
两者一致,表示全匹配到,返回位置i
*/
if (j == n) {
return i;
}
}
return -1;
}
}
KMP字符串匹配法
穷举匹配优化场景1
如果我们知道模式中a和后面的是不相等的,那么第一次比较后,发现后面的的4个字符均对应相等,可见a下次匹配的位置可以直接定位到f了。
穷举匹配优化场景2
注:场景2包括场景1。
由于abc 与后面的abc相等,可以直接得到红色的部分。而且根据前一次比较的结果,abc就不需要比较了,现在只需从f-a处开始比较即可。
获取部分匹配值
"部分匹配"的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么它的"部分匹配值"就是2("AB"的长度)。
// 获取部分匹配值
function kmpGetPartMatchTable(targetStr) {
var aPartMatchTable = [];
var tmpCompareLen = 0;
var tmpPartMatchVal = 0;
var prefix, suffix;//匹配串前缀,后缀
for (var i = 0, j = targetStr.length; i < j; i++) {
if (i == 0) {
aPartMatchTable[i] = 0;
continue;
}
tmpCompareLen = i; //匹配串前缀,后缀最大长度
tmpPartMatchVal = 0;
for (; tmpCompareLen > 0; tmpCompareLen--) {
prefix = targetStr.substr(0, tmpCompareLen);
suffix = targetStr.substr(i - tmpCompareLen + 1, tmpCompareLen);
if (prefix == suffix) { //找到匹配串前缀,后缀最长的共有元素
tmpPartMatchVal = prefix.length; //部分匹配值为:匹配串前缀,后缀最长的共有元素的长度
break;
}
}
aPartMatchTable[i] = tmpPartMatchVal;
}
return aPartMatchTable;
}
一个完整的了KMP字符串匹配算法
穷举匹配优化思路
加上部分匹配值
就形成了KMP字符串匹配算法
// kmp字符串匹配
function kmpGetPartMatchTable(targetStr) {
var aPartMatchTable = [];
var tmpCompareLen = 0;
var tmpPartMatchVal = 0;
var prefix, suffix;//匹配串前缀,后缀
for (var i = 0, j = targetStr.length; i < j; i++) {
if (i == 0) {
aPartMatchTable[i] = 0;
continue;
}
tmpCompareLen = i; //匹配串前缀,后缀最大长度
tmpPartMatchVal = 0;
for (; tmpCompareLen > 0; tmpCompareLen--) {
prefix = targetStr.substr(0, tmpCompareLen);
suffix = targetStr.substr(i - tmpCompareLen + 1, tmpCompareLen);
if (prefix == suffix) { //找到匹配串前缀,后缀最长的共有元素
tmpPartMatchVal = prefix.length; //部分匹配值为:匹配串前缀,后缀最长的共有元素的长度
break;
}
}
aPartMatchTable[i] = tmpPartMatchVal;
}
return aPartMatchTable;
}
function KMP(sourceStr, targetStr) {
var partMatchValue = kmpGetPartMatchTable(targetStr); //部分匹配表
var result = -1;
var i, j, m, n;
n = targetStr.length;
for (i = 0, j = sourceStr.length; i < j; i++) {
for (var m = 0; m < n; m++) {
if (targetStr.charAt(m) != sourceStr.charAt(i + m)) {
if ((m > 0) && (partMatchValue[m - 1] > 0)) {
i += (m - partMatchValue[m - 1] - 1); //设置外层循环开始位置
}
break;
}
}
if (m == n) {
result = i;
break;
}
}
return result;
}
const s = "BBC ABCDAB ABCDABCDABDE";
const t = "ABCDABD";
console.log('str', JSON.stringify(kmpGetPartMatchTable('ABCDABD')), KMP(s,t));
参考链接:
http://www.cnblogs.com/houkai/p/3978550.html
http://kb.cnblogs.com/page/176818/