首页 > 编程语言 >KMP算法

KMP算法

时间:2024-04-10 15:31:12浏览次数:24  
标签:相等 ++ next 算法 prelen KMP 字符串 部分

前言

KMP算法:用于寻找s串中是否包含a串

算法思路

思路:暴力解法中使用 ( i , j ) (i,j) (i,j)遍历,i指向s串,j指向a串,每次匹配一遍a串, i i i指往前了a.length()步后又要回退到( i i i_初始+1)处。而KMP算法利用每次匹配a串过程中的已知信息,使 i i i指针不用回退。如下图所示,如果"ABC"部分A等于C,则可以直接跳过A部分的比较,而 i i i也不用回退,继续比较子串的剩余部分即可。
思路图
实现

  1. a串拥有一个int[] next=getNext()数组。
  2. i i i遍历s串。
  3. j j j指向a串,且 j j j是跳变的。//所以只有一层for循环
  4. 如果当前 s [ i ] = a [ j ] s[i]=a[j] s[i]=a[j]则 i i i和 j j j均向前移动。
  5. 如果不相等,则将 j j j指针跳到 n e x t [ j − 1 ] next[j-1] next[j−1]处。注意,此处是 w h i l e while while,只要不相等就一直往前跳。如果退出情况是相等,则 j j j往后移一格(因为下一轮循环会 i i i++);如果退出之后仍然不相等,则表明 j j j移动到a串的头部了,此时不做处理,开始下一轮的 i i i++循环。

解释如果不相等,则将 j j j指针跳到 n e x t [ j − 1 ] next[j-1] next[j−1]处:如果 s [ i ] ! = a [ j ] s[i]!=a[j] s[i]!=a[j],则看a串[0,j-1]部分的最长相同前后缀,可以跳过开头的相同部分。

getNext

介绍:返回子串a的next数组。next[ i i i]表示[0, i i i]区间的最长相同前后缀的长度。
思路讲解
在这里插入图片描述

  1. 如Fig.1所示,已知 R R R部分元素的next值,R部分最长公共前后缀的长度为 R L R_L RL​=next[6]=3。所以求next[7],可以先比较next[ R L R_L RL​]是否与a[7]相等,如果相等,那么next[ R L R_L RL​]=next[6]+1。图中不相等,故要继续求解。
  2. 如Fig.2所示继续观察串R部分,如果R部分①所画双横线部分相等,则看a[2]是否和a[7]相等,如果相等则next[7]=3。如果①部分不相等则看②部分,如果②所画双横线部分相等,则看a[1]是否和a[7]相等,如果相等则next[7]=2。所以总结起来就是:(下述伪代码没有考虑很多细节,只为理解方便)
//R->缩为自己的最长公共前缀,即
R_L=next[R_L]=3
if(a[R_L]==s[7]) next[7]=R_L+1;
else{
   R_L = next[R_L];//这里还要考虑是否已经为0,如果已经为0,则代表没有和s[7]相等的部分,next[7]直接为0
}

实现

public void getNext(int[] next,String s){
        next[0]=0;
        int i=1;
        int prelen=0;//当前共同前后缀长度,即串"(xxx)i"的(xxx)部分的共同前后缀长度为prelen
        //此时,需要看s[prelen]和i是否相等
        while(i<s.length()){
            if(s.charAt(i)==s.charAt(prelen)){
                next[i] = ++prelen;//是++i而不是i++
                i = i+1;
            }
            else{
                if(prelen==0){
                    next[i]=0;
                    i = i+1;
                }else{
                    prelen = next[prelen-1];
                }
            }
        }
    }

注释:还有一种双指针实现,没有上面容易理解讲解

KMP用文字解释起来好无力,看动画解释比较好。确实绕,看代码比看文字强,好难解释/(ㄒoㄒ)/~~

具体题目

一、28题(实现 strStr())

题目描述
实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1: 输入: haystack = “hello”, needle = “ll” 输出: 2
示例 2: 输入: haystack = “aaaaa”, needle = “bba” 输出: -1

题解

一些备注

在这里插入代码片

算法思路
易错点
备注

  • Arrays.toString(next);//输出数组,避免遍历输出
  • 最好记住一组很好的案例,这样一边写程序一边核对案例就不会出错。
①对于getNext: abacabab
②对于主程序:abacabab 和 abab

二、459题(重复的子字符串)

题目描述
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
示例 1:
输入: “abab”
输出: True
解释: 可由子字符串 “ab” 重复两次构成。

在这里插入代码片

总结

若干总结。

标签:相等,++,next,算法,prelen,KMP,字符串,部分
From: https://blog.csdn.net/qq_43969379/article/details/137591047

相关文章