KMP学习(子字符串在主字符串中的首次出现的位置)

自学记录所用,不对之处望请斧正

引入:KMP算法是为了实现index函数(子字符串在主字符串中的首次出现的位置)如下图所示
在这里插入图片描述
若规定字符串索引从0开始,则子字符串在主字符串中的首次出现的位置为2;

index函数实现:

算法一:暴力算法
从主串起始位置依次向后截取与子串长度相同的字符串,在与子串进行比较。代码如下:

int index(String s,String t){//s为主串 t为子串
        if (s.length() < t.length())return -1;
        int i = 0;
        while (i < s.length() - t.length() ){
            String temp = s.substring(i,i + t.length());
            if (t.equals(temp))return i;
            i++;
        }
        return -1;
    }

算法二:滑动窗口算法(朴素匹配)
将子串首个字符与主串的字符分别比较,若不同则比较下一个,若相同则将主串指针和子串指针分别后移依次比较是否相同。代码如下:

int index(String s,String t){
    if (s.length() < t.length())return -1;
    int i = 0;
    int x = 0;
    while (i < s.length() - t.length() ){
       if (s.charAt(i) == t.charAt(x)){
           int k = i + 1;
           int j = 1;
           while (j < t.length() && s.charAt(k) == t.charAt(j)){
               k++;
               j++;
           }
           if (j == t.length())return i;
       }
       i++;
    }
    return -1;
}

或者这样也可以:

int index(String s,String t){
        if (s.length() < t.length())return -1;
        int i = 0;//主串指针
        int x = 0;//子串指针
        int k = 0; //记录主串位置
        while (i < s.length() && x < t.length()){
            if (s.charAt(i) == t.charAt(x)){
                i++;
                x++;
            }else {
                k++;
                i = k;
                x = 0;
            }
        }
        if (x == t.length())return k;
        return -1;
    }

两个代码实现原理一样。

算法三:KMP算法
为了减少朴素算法(算法二)的比较次数,KMP出现了!
在这里插入图片描述
如上图,当子串与主串比较到箭头所指位置时,主串与子串对应字符不相同,此时观察子串箭头位置左部分有AB这一组相同的前后缀,不难发现我们只需要移动子串位置使前缀到达移动前的后缀位置即可在正确的前提下减少比较次数。如下图所示:
在这里插入图片描述
在主观视觉上我们觉得子串向右移动而实际上是箭头(子串指针)向左移动到前缀的后一个位置,而且我们可以直接获得子串的每一个位置的前后缀相同时的长度,有意思的地方来了,我们甚至可以直接声明一个数组用来存放子串在该位置与主串不相同时应该左移到子串的哪个位置!我们的next数组来了!
如何获取next数组的每一个元素呢!(假设字符串从1开始)
手算:计算前后缀相同时的长度 + 1;next[ i ]最多比next[ i - 1 ]大1;
算法获取:代码如下:

void getNext(char c[],int[] next){
            next[1] = 0;
            int i = 1;
            int j = 0; //j为了记录next[i]的状态 
            while (i < c.length){
                if (j == 0 || c[i] == c[j])next[++i] = ++j;
                else j = next[j];
            }
    }

然后就可以改进算法了得到KMP算法了

int index(String s,String t){
        if (s.length() < t.length())return -1;
        int i = 0;//主串指针
        int x = 0;//子串指针
        int k = 0; //记录主串位置
        int[] next = new int[t.length + 1];
        getNext(s.toCharArray(),next);
        while (i < s.length() && x < t.length()){
            if (s.charAt(i) == t.charAt(x)){
                i++;
                x++;
            }else {
               x = next[x];
            }
        }
        if (x == t.length())return k;
        return -1;
    }

KMP优化:KMP的优化就是next的优化,即在赋值next的各个值时查看前面有没有相同字符若有则直接用其数值。获得nextval
在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值