KMP算法

目录

1.概念  

1.为什么主串不回退

2.j回退的位置

3.过程

2.next数组

3. 已知next[i] = k;怎么求next[i+1] = ?

4.next数组的优化


1.概念  

是一种改进的字符串匹配算法,

核心:利用匹配失败后的信息,尽量减少模式串和主串的匹配次数达到快速匹配的目的

特点:主串i不会回退,j不会移动到0号位置

1.为什么主串不回退

主串回退和子串的第一个字符不一定相同

2.j回退的位置

有next数组决定,next对应位置的值,就是j的值,避免了每次从0开始匹配

3.过程

KMP算法_第1张图片

 

KMP算法_第2张图片

不匹配时,找到前一个对应的next==0

KMP算法_第3张图片

子串跳过0个字符,剩下的继续比较,不匹配时,找到前一个对应的next==2

KMP算法_第4张图片

子串跳过2个字符,剩下的继续比较,

KMP算法_第5张图片

子串遍历完成,返回i-j

2.next数组

保存匹配失败后,子串可以跳过的字符个数

本质:是匹配的子串中,前后缀匹配的相同的字符串的长度

next[i]=k  k就是j要移动的位置

规则:

  • 找匹配成功部分的两个相等的真字符串,一个以下标0开始,一个以下标j-1结束,字符串的长度为k
  • nexr[0]=-1 next[1]=0

KMP算法_第6张图片

 

next数组的练习:

练习 1: 举例对于”ababcabcdabcde”, 求其的 next 数组?

-1 0 0 1 2 0 1 2 0 0 1 2 0 0

 KMP算法_第7张图片

3. 已知next[i] = k;怎么求next[i+1] = ?

KMP算法_第8张图片

 

首先假设: next[i] = k 成立,那么,就有这个式子成立: P0...Pk-1 = Px...Pi-1;得到: P0...Pk-1 = Pi-k..Pi-1(两个字符串相等)

k-0=i-x==> x=i-k;

==> p[0]..p[k-1]=p[i-k]..p[i-1]

a. 假设:p[k]=p[i]

==> p[0]..p[k]=p[i-k]..p[i]

==>next[i+1] = k+1 字符串长度在原来的基础+1

b.p[k]!=p[i]

KMP算法_第9张图片

 

此时回退的不一定是要找的位置,继续回退,到了0下标

一直回退找p[i]==p[k]

步骤:

public class Test {
    /**
     *
     * @param str  主串
     * @param sub  子串
     * @param pos 从pos位置开始匹配
     * @return  找到子串在主串当中的下标
     */
    public static int KMP(String str,String sub,int pos){
        //两个字符串不为空,pos位置合法
        if(str==null || sub==null)
            return -1;
        int lenStr=str.length();
        int lenSub=sub.length();
        if(lenStr==0 || lenSub==0)
            return -1;
        if(pos<0 || pos>=lenStr)
            return -1;
        int[] next=new int[lenSub];
        //得到next数组
        getNext(sub,next);
        int i=pos;  //从pos位置开始遍历主串
        int j=0;//遍历子串
        //i,j位置合法
        //相同,继续匹配下一个字符
        //如果到-1,要增加
        while (i=lenSub){
            //遍历完,子串在主串中的位置
            return i-j;
        }
        return -1;
    }

//得到next数组
//相等next[i]=k+1   i++ k++
//不相等回退
//       k      i-1 i
// a b c d a b c d f
    private static void getNext(String sub, int[] next) {
        next[0]=-1;
        next[1]=0;
        int i=2;//提前走了一步
        int k=0;//前一项的k
        //遍历子串
        for(;i< sub.length();i++){
            //p[i-1]==p[k]
            //k回退到-1位置
            if(k==-1 ||sub.charAt(i-1) ==sub.charAt(k)){
                next[i]=k+1;
                k++;
                i++;
            }else{
                //k往回走
                k=next[k];//回到k对应位置的next的位置
            }
        }
    }

    public static void main(String[] args) {
        System.out.println(KMP("ababcabcdabcde","abcd",0));
        System.out.println(KMP("ababcabcdabcde","abcde",0));
        System.out.println(KMP("ababcabcdabcde","abcdef",0));
    }
}

4.next数组的优化

一次回退到位

KMP算法_第10张图片

 1.回退到的位置和当前字符一样,写回退位置的nextval

2.回退到的位置和当前字符不一样,写当前字符原来的next值

 

你可能感兴趣的:(算法)