js实现kmp算法_javascript使用KMP算法解决字符串匹配问题

本文介绍了如何使用JavaScript实现KMP算法解决字符串匹配问题。通过避免暴力匹配中的大量回溯,KMP算法提高了查找模式串在文本串中出现位置的效率。文章详细讲解了KMP算法的核心思想,即利用next数组记录模式串中前后最长公共子序列的长度,从而减少重复计算。
摘要由CSDN通过智能技术生成

字符串匹配问题::

1.有一个字符串 str1= "BBC ABCDAB ABCDABCDABDE",和一个子串 str2="ABCDABD"

2.现在要判断 str1 是否含有 str2, 如果存在,就返回第一次出现的位置, 如果没有,则返回-1

暴力匹配算法

如果用暴力匹配的思路,并假设现在str1匹配到 i 位置,子串str2匹配到 j 位置,则有:

1.如果当前字符匹配成功(即str1[i] == str2[j]),则i++,j++,继续匹配下一个字符

2.如果失配(即str1[i]! = str2[j]),令i = i - (j - 1),j = 0。相当于每次匹配失败时,i 回溯,j 被置为0。

3.用暴力方法解决的话就会有大量的回溯,每次只移动一位,若是不匹配,移动到下一位接着判断,浪费了大量的时间。(不可行!)

4.暴力匹配算法实现.

KMP算法介绍

1.KMP是一个解决模式串在文本串是否出现过,如果出现过,最早出现的位置的经典算法

2.Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP算法”,常用于在一个文本串S内查找一个模式串P 的出现位置,这个算法由Donald Knuth、Vaughan Pratt、James H. Morris三人于1977年联合发表,故取这3人的姓氏命名此算法.

3.KMP方法算法就利用之前判断过信息,通过一个next数组,保存模式串中前后最长公共子序列的长度,每次回溯时,通过next数组找到,前面匹配过的位置,省去了大量的计算时间

4.参考资料:很详尽KMP算法(厉害) - ZzUuOo666 - 博客园

3d817928860eb026673049aa475b63d0.png

d8f6472ed34a97bf8582f44a2c4d296d.png

121abcea79abdd23f106678484538f73.png

71408e724e17782304786a21e1b495ca.png

e25f79d53404429b92d352f5e608f84e.png

关于kmp核心算法点 j = next[j - 1];

可以参考文章:

很详尽KMP算法(厉害) - ZzUuOo666 - 博客园​www.cnblogs.com

或者看我手写的。。

f8d5aa6c4ef8fcab3b71e35a71977b9c.png

ce01539cffd120b28a784d37926bc644.png
/**
 * 
 * 
 KMP算法解决字符串匹配问题
 * 
 * 
 */


//暴力匹配算法实现
function violenceMatch(str1, str2) {
    let s1 = str1.split('');
    let s2 = str2.split('');

    let s1Len = s1.length;
    let s2Len = s2.length;

    let i = 0;//i索引指向s1
    let j = 0;//j索引指向s2
    while (i < s1Len && j < s2Len) {//保证匹配时,不越界
        if (s1[i] === s2[j]) {//匹配成功
            i++;
            j++;
        } else {//没有匹配成功
            i = i - (j - 1);
            j = 0
        }
    }
    //判断是否匹配成功
    if (j === s2Len) {
        return i - j;
    } else {
        return -1;
    }
}

//获取子串的部分匹配值表
function kmpNext(dest) {
    //创建一个next数组保存部分匹配值
    let next = new Array(dest.length);
    //如果字符串是长度为1,部分匹配值就是0
    next[0] = 0;
    for (let i = 1, j = 0; i < dest.length; i++) {
        //当dest.chatAt(i) !== dest.chatAt(j),我们需要从next[j-1]获取新的j
        //直到我们发现有dest.chatAt(i) === dest.chatAt(j)成立才退出
        //这是kmp算法的核心点
        //分析见手写图
        while (j > 0 && dest.charAt(i) !== dest.charAt(j)) {
            j = next[j - 1];
        }

        //dest.charAt(i) === dest.charAt(j)满足时,部分匹配值就+1
        if (dest.charAt(i) === dest.charAt(j)) {
            j++;
        }
        next[i] = j;
    }
    return next;
}

//kmp搜索算法
/**
 * 
 * @param {源字符串} str1 
 * @param {子串} str2 
 * @param {子串对应的部分匹配表} next 
 * @returns 如果是-1就是没有匹配到,否则返回第一个匹配位置
 */
function kmpSearch(str1, str2, next) {
    //遍历
    for (let i = 0, j = 0; i < str1.length; i++) {
        //需要处理str1.charAt(i) !== str2.charAt(j),去调整j的大小
        //KMP算法核心点
        while (j > 0 && str1.charAt(i) !== str2.charAt(j)) {
            j = next[j - 1];
        }

        if (str1.charAt(i) === str2.charAt(j)) {
            j++;
        }

        if (j === str2.length) {//找到了
            return i - j + 1;
        }
    }
}

let str3 = 'BBC ABCDAB ABCDABCDABDE';
let str4 = 'ABCDABD';
let next = kmpNext(str4)
console.log('ABCDABD的匹配值数组为:', next)
console.log('暴力匹配算法:', violenceMatch(str3, str4));
console.log('kmp匹配算法:', kmpSearch(str3, str4, next));

测试:

4bd32aa400641520df8b19e037e6af1d.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值