算法第二讲(字符串匹配KMP)

算法第二讲(字符串匹配KMP)

从2019年9月开始,会把《数据结构》经典的算法介绍一遍。加油,89lovelc

问题介绍
  • 在一段字符串里面匹配子串是否存在的问题,比如说"89lovelc" 里面有没有lc,89或者el的字符串。
问题分析
  • 虽然我们介绍KMP算法,但是我们不妨先使用暴力美学做一下这个问题,正所谓大力出奇迹,我们可以进行遍历要进行查找的字符串,从第一个字符开始和子串第一个字符开始比较,相等就进行比较第二个,以此类推,直到完全匹配成功。不成功的话,将游标移到查找的字符串的第二个,重新开始遍历。直到最后成功。
  • 暴力图解
  • 在这里插入图片描述
  • 但是我们有没有一种办法,从字串入手进行分析,让其跳过一些已知的字母呢?
算法思想
  • 如上面的暴力破解的图来看的话,第一张到第二张图的时候,其实我们挨个遍历,我们已经知道了前面的字母,而且可以调到第二个ad的这里开始遍历的。如下图,这样我们就可以不再是单一的遍历了。
    在这里插入图片描述
  • 得到next数组
    • 所以通过上面的列子,我们可以对字符串str进行解析,得到一个数据组,**表示的意思是在字符串j的位置之前有k个数达到 str[0]str[1]…str[k-1] = str[j-k]…str[j-2]str[j-1] **( j> k,不然就是子串相等了,没有比较的意思)。
    • 在这里插入图片描述
    • 这样就可以得到next这个数据进行下一步的计算了
  • 通过next数组进行匹配
    • 在这里插入图片描述
    • 图A 我们使用i进行遍历原始串,使用j进行遍历匹配串,开始进行一一匹配
    • 图B 但是匹配到最后的时候,我们发现有d 和 e 不能进行匹配,匹配失败,但是我们不用进行从头开始,在图B中的数字就是我们的next数组,我们取到e所对应的k值,就是2 ,让 j = 2 相当于我们的匹配串整体往右滑
    • 图C 就是我们将 j = 2 之后匹配图,这个时候我们可以继续进行 i,j 的匹配
    • 如果匹配成功,i - str.length 的index就是开始匹配下标
    • 如果匹配失败,return -1
代码实现
package com.lovelc;

/**
 * KMP 看毛片?
 */
public class KMP {


    /**
     * 得到next 数组
     *
     * @param string
     * @return
     */
    public static int[] getNext(String string) {
        int[] next = new int[string.length()];

        //j 进行遍历string
        int j = 0;
        //k 进行记录匹配个数
        int k = -1;
        next[0] = -1;

        char[] chars = string.toCharArray();

        while (j < chars.length - 1) {

            if (k == -1 || chars[j] == chars[k]) {
                j++;
                k++;
                next[j] = k;
            } else {
                // 不能进行匹配 就进行回退到 子串进行匹配
                k = next[k];
            }
        }
        return next;
    }


    /**
     * 进行匹配
     * @param s 被匹配串
     * @param find 匹配串
     * @return -1 匹配失败  其他为 匹配开始的index
     */
    public static int KMPIndex(String s, String find) {
        int[] next = getNext(find);
        int i = 0;
        int j = 0;

        while (i < s.length() && j < find.length()) {
            if ( j == -1 || s.charAt(i) == find.charAt(j) ) {
                i++;
                j++;
            } else {
                // 不能进行匹配 子串右滑
                j = next[j];
            }

        }

        // 匹配成功
        if (j == find.length()) {
            return i - find.length();
        }

        return -1;

    }


    public static void main(String[] args) {

        System.out.println(KMPIndex("adcaddaadcade","adcade"));

        System.out.println(KMPIndex("djkalsdjkld","ssdd"));
    }
}

运行结果

在这里插入图片描述

总结

KMP 说起来还是很简单的,运用到代码里面,还是有几个地方需要去理解清楚的,想明白。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值