KMP算法

一种字符匹配算法

核心思想

利用匹配失败后的信息,尽量减少模式串与主串的匹配次数,以达到快速匹配的目的。

匹配失败后主串指针不会进行回溯,利用已匹配部分中的公共前后缀(next数组)来调整模式串的指针位置,以此加速下一次匹配。

例:给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 。

示例 1:

输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。

构造Next数组

一维数组next[len],在位置 i 处存储的是已匹配字符串 needle(0, i-1)的最长公共前后缀长度。

eg, “abctdhabch”, next[9] = 3

构造步骤:

        1. 初始化next[0] = -1(代表没有前缀)

        2. 设变量t = -1 —— t 代表当前匹配到的前缀的结束位置。

        3. 设变量 j=0 —— 利用变量 j 遍历模式串以寻找各个位置的最长公共前后缀

        4. 使用前缀位置 t 和遍历位置 j 来更新 next [ j ]

            如果已经没有可以匹配的前缀位置了(即 t = -1),那么证明(0, j)子串的最长公共前缀为0。然后,更新 t、j、next [ j ] —— t++,j++,next [ j ] = t。

            如果 needle.chatAt(t) == needle.charAt(j),那么匹配成功,最长公共前后缀为更新后的已匹配前缀长度—— t++, j++, next [ j ] = t。

            如果匹配失败了,且还有可匹配的前缀位置( t>0, needle.chatAt(t) != needle.charAt(j)),那么则需要回退前缀匹配位置 t,尝试用前一位置的最长公共前后缀进行匹配。

匹配过程

匹配步骤

        1. 初始化:r 表示当前匹配到的模式串的位置,

                          i 表示当前匹配到的主串的位置

        2. 进行循环匹配,结束条件:模式串完全匹配或主串遍历完毕

                          while (r < needle.length() && i < haystack.length())  

        3. 在每次循环时判断以下情况:

                当当前前缀匹配位置已经没有可匹配的位置时(r < -1),或者 当主串与模式串匹配成功时,——> r++, i++.

                当有可匹配的位置但却匹配失败时,则根据next [ r ] 回退 r 的匹配位置,r = next [ r ]

        4. 当循环结束后返回结果

                判断是否完全匹配 (r == needle.length()), 若是,则返回起始位置 i - r

                                                                                  若不是,则返回 -1

代码

public class Solution{
    public int strStr(String haystack, String needle){
        if(needle.length() < 1)
            return 0;
   
        //构建公共前后缀长度数组next
        int len = needle.length();
        int[] next = new int[len];
        next[0] = -1;
        int t = -1;
        int j = 0;
        while(j < len-1){
            if(t<0 || needle.charAt(t) == needle.charAt(j)){
                ++t;
                ++j;
                next[j] = t;
            }else
                t = next[t];
        }
        
        //匹配过程
        int r = 0;
        int i = 0;
        while(r < needle.length() && i < haystack.length()){
            if(r<0 || needle.charAt(r) == haystack.charAt(i)){
                ++r;
                ++i;
            }else{
                r = next[r];
            }
        }
        //返回结果
        if(r == needle.length()){
            return i-r;
        }else
            return -1;
    }
}

      时间复杂度O(m+n)        

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值