代码随想录刷题day09

代码随想录刷题day09

补KMP,当时没咋看懂,多看了几遍,有了一点自己的理解。

在主串中寻找子串,next数组(最长前缀数组)

前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串

后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串

aabaaf 来举例:

前缀有 a,aa,aab,aaba,aabaa,

后缀有f,af,aaf,baaf,abaaf

最长相等前后缀,前缀和后缀中相等的长度

a: 0 a没有前缀也没有后缀

aa: 1 a和a

aab: 0

aaba :1

aabaa: 2

aabaaf : 0

上面得到的这个序列 [0,1,0,1,2,0]就是前缀表

为什么要用前缀表?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SpdONgco-1667743140552)(代码随想录刷题.assets/image-20221106203552072.png)]

下标5之前这部分的字符串(也就是字符串aabaa)的最长相等的前缀 和 后缀字符串是 子字符串aa ,因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的前缀的后面从新匹配就可以了。

看了好几遍这段话,终于有点看明白了。最长相等前后缀记录了相等的位置,后缀的部分匹配不上了,跳到相等的前缀的后面,也就是b这个位置,因为aa是之前已经匹配过了不同在匹配。

代码上如何求这个前缀表呢?

1.初始化

2.处理前后缀不相同的情况:找到前一个需要回退的位置进行回退

3.处理前后缀相同的情况

4.更新next数组

private void getNext(int[] next, String s) {
        int j = 0;//j指向前缀末尾位置,还代表最长前后缀长度,i指向后缀末尾位置
        next[0] = 0;
        for (int i = 1; i < s.length(); i++) {//i从1开始,以为要比较前后缀末尾是否相同的
            while (j > 0 && s.charAt(j) != s.charAt(i)) //前后缀不相同的情况,
                j = next[j - 1];
            if (s.charAt(j) == s.charAt(i)) //前后缀相同的情况,因为j代表了最长前后缀的长度,所以需要++
                j++;
            next[i] = j; 
        }
    }

得到next数组以后 如何利用next数组进行匹配呢

i指向文本串,j指向next数组,当遇到不匹配的时候 去找next数组中前一个记录的值;知道j指向了next数组的后面一位,说明找到了匹配的子串。

完整代码

class Solution {
    public int strStr(String haystack, String needle) {
        if(needle.length()==0) return 0;
        int [] next=new int[needle.length()];
        getNext(next,needle);

        int j=0;//j 指向next数组的第一位

        for(int i=0;i<haystack.length();i++){
            while(j>0 && needle.charAt(j)!=haystack.charAt(i)){
                j=next[j-1];
            }
            if(needle.charAt(j)==haystack.charAt(i)) j++;
            if(j==needle.length()) return i-needle.length()+1;
        }

        return -1;
    }

    private int[] getNext(int[] next, String s){
        int j=0;//指向前缀末尾的位置,还代表最长前后缀的长度
        next[0]=0;

        //i 指向后缀末尾的位置,因为要比较 所以从1 开始
        for(int i=1;i<s.length();i++){
            while(j>0 && s.charAt(j)!=s.charAt(i)){
                //前后缀不相等 j跳到 next数组前一个记录 所记录的位置
                j=next[j-1];
            }
            if(s.charAt(i)==s.charAt(j)) j++;//前后缀相等的情况,j还代表的最长相等前后缀的长度 所以还需要++

            next[i]=j;//更新next 数组 当前i指向的数组 记录最长前后缀的长度  i++的操作已经在循环中做了
        }
        return next;
    }
}

reference
代码随想录 (programmercarl.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值