字符串也过七夕?KMP算法帮助字符串找到ta的另一半!

七夕来临,不知巧合还是咋地,突然在LeetCode刷到不少字符串匹配的题目,本来抱着大力出奇迹心理的我一直以来都是暴力破万法,不料也卡在了时间复杂度上,于是拾起了久久不用的kmp算法。

字符串匹配

先来看一个场景:
现在有两个字符串,S1和S2,现在想知道S1中是否有S2。如何判断?
当然,最先肯定会想到的是indexOf()函数,亦或是正则表达式。然而,当需要我们自己编写算法时,也不能傻了眼,接下来认识一下几种编写匹配算法的方式:
1、暴力搜索
简单易懂的算法
算法描述:在原字符串搜索模式串,当发现无法匹配的情况,就一夜回到解放前,继续从原来的起始位置的下一个进行对模式串搜索。直到搜索成功或搜索完原字符串,下面说明一个例子:
每次匹配错误主串都要回头
程序如下:

public static int bf(String s1 , String s2){
        int result = -1;
        int l1 = s1.length();
        int l2 = s2.length();
        if(l1 == 0 || l2 == 0 || l1 < l2){
            return -1;
        }
        A:for(int i = 0 ; i <= l1 - l2 ; i++){
            for(int j = 0 ; j < l2 ; j++){
                if(s1.charAt(i + j) != s2.charAt(j)){
                    continue A;
                }
            }
            result = i;
        }
        return result;
    }

其返回值为主串中第一次匹配模式串的索引
可见,这种做法虽然简单易懂,容易实现,但是比较笨拙,为此,我们可以引进KMP算法

KMP算法

观察到上述移动过程,可以发现:有很大的改进余地,每一次判断都浪费了之前已经判断出来的某些信息,为此,我们对其进行改进:
可以通过一个next数组,保存前面已判断出的信息,能做到使主串中的i不用往回进行回溯

代码如下:

public static int kmp(String str,String pat){
        int[] next = next(pat);
        for(int i = 0 ,j = 0 ; i< str.length();i++){
            while(j > 0 && str.charAt(i)!= pat.charAt(j)){
                j = next[j - 1];
            }
            if(str.charAt(i) == pat.charAt(j)){
                j++;
            }
            if(j == pat.length()){
                return i - j + 1;
            }
        }
        return -1;
    }
    public static int[] next(String pat){
        int[] next = new int[pat.length()];
        next[0] = 0 ;
        for(int i = 1 , j = 0 ; i < pat.length(); i++){
            while (j > 0 && pat.charAt(i) != pat.charAt(j)){
                j = next[j - 1];
            }
            if(pat.charAt(i) == pat.charAt(j)){
                j++;
            }
            next[i] = j;
        }
        return next;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值