KMP算法

        KMP算法主要是解决包含问题,特别是在字符串方面用的比较多,主要就是看在一个字符串里面看是否包含一个字串。

        要查看一个字符串里面是否包含另一个字串,大体上分为两步。1,首先拿到字串,并且拿出它的每一个字符,去算它的最长前缀和最长后缀的匹配长度,并返回next数组。2,在此基础上去比较字两个字符串。

第一步:拿子字符串去算最长前缀和最长后缀的匹配长度。

怎么理解呢?

比如说下面这个就是我们的子串。

首先拿第一个字符a,他前面没有字符了,所以我们规定它为-1。

然后拿到第二个字符串它前面自由一个字符a,我们规定他为0。

拿到第三个字符,他前面有ab,由于a和b不相等,所以为0。

来到字符串a(下标为3),它前面的串为abc,前缀a和后缀c不想等,还可以走ab和bc不相等,这时不能再走了,所以为0。

来到字符b(下标为4),它前面的字符为abca,a和a相等,此时为1,看还有没有比它大的,ab和ca不相等,再走,abc和bca不相等,不能再走了,所以为1。

此时来到字符d他前面的串为,abcab,a和b不等,在往前走一走,ab和ab一样,长度为2,再往前走看看有没有abc和cab,abca和bcab都不相等,所以为2。

所以最后返回next数组为{-1,0,0,0,1,2}。

总结:其实主要就是看前面有没有重复的。代码实现其实用的归纳法。

 第二步:去比较两个字符串

假如说我们的两个字串为"abcabct"和"abcabcz",有两个指针index1,和index2,两个从0开始比较,一直来到不同位置为止,当匹配到不同的字符时就停下,然后前面第一步不是算出来了个next数组吗,这时候就用到了,利用前面的方法可以直观的看出来z位置的next数组中的值应该为3,然后index1不动,index2直接跳到3位置来接着和index1进行比较。其实从这个例子可以看出来next主要就是记录前面有没有重复串,如果有可以少比较很多。

 关于计算next数组用的是数学归纳法,

比如说一个数组"abab c ababtk"  假如说我们要算k位置的长度,这时假设k前面的一个我们应该已经知道了,可以直观的看出t位置应该为4,那么这时4位置上的数和t等不等,这里可以看出来不相等的,一个是c一个是t,就直接为0。假如说是 "abab c abab a k"依然是计算k位置c和a不等,再往前分,c位置的应该是2,来到2的位置a和a相等,就直接2+1为3,所以k对应的next数组的值应为3。

代码:

   public static int[] getNext(char[] str2){
        int[] next = new int[str2.length];
        next[0] = -1;
        next[1] = 0;
        int i = 2;
        int cn = 0; //前半重复的的后一个
        while(i < next.length){
            if(str2[i -1] == str2[cn]){ //当前位置的前一个,等于前半重复的后一个,直接加一
                next[i++] = ++cn;
            }else if(cn > 0){
                cn = next[cn];  //不相等就再往前分
            }else {   //到最后也没分到,就表示没有了
                next[i++] = 0;
            }
        }
        return next;
    }

    public static int getIndexOf(String str1,String str2){
        if(str1 == null || str2 == null || str1.equals("") || str2.equals("")){
            return -1;
        }
        char[] c1 = str1.toCharArray();
        char[] c2 = str2.toCharArray();
        int index1 = 0;
        int index2 = 0;
        int[] next = getNext(c2);
        while(index1 < str1.length() && index2 < str2.length()){
            if(c1[index1] == c2[index2]){  //如果字符串相等,两个指针就往后走
                index1++;
                index2++;
            }else if(next[index2] == -1){ //  前面无重复字符串的情况
                index1++;
            } else{      //这种情况是前面有重复串的情况
                index2 = next[index2];
            }
        }
        return index2 == c2.length ? index1 -index2 : -1;  //如果idnex2来到了跟数组长度一样,就说明找到了,否则就是没找到
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值