leetcode 每日一题 4.20(已更新)

leetcode28. 实现 strStr()

字符串匹配问题,想到采用暴力循环对比方法和KMP方法,暂时上传朴素方法,KMP待学习完之后发布= =
KMP算法已更新在朴素暴力算法的下方,是个人的一些理解,如有错误的地方敬请斧正
代码中最难以理解的部分是k=next[k] 这一句,如果阅读后有没明白的地方可以去https://www.cnblogs.com/dusf/p/kmp.html这位作者的博客,讲的非常详细,作者本人也受到这篇博文的启发很多

class Solution {
    public int strStr(String haystack, String needle) {
        int len_n = haystack.length(), len_p = needle.length();
        if(len_p == 0) {
            return 0;
        }//题意,needle == 0时直接返回0
        char[] s = haystack.toCharArray()
        char[] p = needle.toCharArray();
        //上面两行的作用是toachararray方法,简单来讲是将字符串数组转化为字符函数
        for (int i = 0; i <= len_n - len_p; i++) {
            int a = i, b = 0;
            while (b < len_p && s[a] == p[b]) {
                a++;
                b++;
            }//匹配(双指针思想)
            if (b == len_p) {
                return i;
            }//匹配成功
        }
        return -1;
    }
}

KMP解法↓
先直接上代码和注释,后面有思路

class Solution {
    public int strStr(String haystack, String needle) {
        if(needle.length() == 0) {
            return 0;
        }
        int n = haystack.length(),m = needle.length();//读取长度
        haystack = " " + haystack;
        needle = " "+ needle;//这里参考leetcode 宫水三叶 的用法,在原串和匹配串前面都加空格,使下标从1开始,更易理解一点

        char s[] = haystack.toCharArray();
        char p[] = needle.toCharArray();
        int next[] = new int [m+1];//构建next数组
        for(int i = 2,j = 0;i <= m;i++) {
            while(j > 0 && p[i] != p[j+1]) {
                j = next[j];
            }//每次循环结束后更新i的值(i+=1),使next数组的第i位其始终与符合条件的haystack前缀的最后一位相等(回溯)
            if(p[i] == p[j+1]) {
                j++;//成功的话,j++(指针后移判断下一个字符);再让i++与其作比较
            } 
            next[i] = j;//匹配不成功时,将j(前缀的长度)赋给next[i];
        }
        for(int i = 1,j = 0;i <= n;i++) {
            while(j > 0 && s[i] != p[j+1]) {
                j = next[j];//匹配不成功,寻找之前匹配的位置
            }
            if(s[i] == p[j + 1]) {
                j++;//匹配成功情况,两个指针同时后移
            }
            if(m == j) {
                return i-j;//全部匹配成功,直接返回下标
            }
        }
        return -1;
    }
}

代码写了这么多,那么下面讲解思路,KMP的重点在于当某一个字符与被匹配串中不匹配时,需要知道j指针要移动到什么地方
//下图来自于https://www.cnblogs.com/dusf/p/kmp.html这位博主,方便各位理解
这是指针变化的点,即第一次找到不同节点

在C和D不匹配的时候,由于发现前面有一个A,我们显然应该把j挪动到第1位

下图也是一样的情况:

我们可以把指针j挪到第二位,显然是因为AB字母相同
在这里插入图片描述

因此,我们可以说,当匹配失败的时候,j要移动的下一个地方最前面的k个字符和j之前的最后k个字符是相等的,数学公式表示为:
needle[0 ~ k-1] == needle[j-k ~ j-1]
觉得不好理解的话,上图:

也就是说能推出以下结论:
因为当haystack[i] != needle[j]时
有haystack[i-j ~ i-1] == needle[0 ~ j-1]
而又由needle[0 ~ k-1] ==needle[j-k ~ j-1]
必然能推出haystack[i-k ~ i-1] == needle[0 ~ k-1]这一结论;从而理解KMP算法。
但是在这样的公式中,如何得到k值是一个关键
由于在被查找关键字的每一个位置都可能发生不匹配,也就是说我们要计算每一个位置j所对应的k,所以用一个数组next来保存;
不好理解的关键代码:**next[j] = k;**所表示的是当 haystack[i] !=needle[j]时(即第一个不重复的字符出现开始),j指针会到达的恒下一个位置,因为k值实际上是j位前的字串的最大重复子串的长度
我们仔细观察下面两张图
在这里插入图片描述
对比
在这里插入图片描述
我们可以发现一个规律,当子串needle[k] == needle[j]时,可以推出公式
next[j+1] == next[j]+1

那么当needle[k] != needle[j]的时候呢,会有下图这种情况
在这里插入图片描述
从代码上来看的话,本图的含义即是k = next[k];原因如下图所示:
在这里插入图片描述
按上面的图例来讲,我们已经不可能找到[ A,B,A,B ]这个最长的后缀串了,但我们还是可能找到[ A,B ]、[ B ]这样的前缀串的。所以这个过程像不像在定位[ A,B,A,C ]这个串;当C和主串不一样了(也就是k位置不同时),就把指针移动到next[k]的位置上

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵奕升

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值