代码随想录Day9 | 28. 实现 strStr(),459. 重复的子字符串

Day9

前言

来到了所谓的KMP算法,全新的未知领域

文章:代码随想录

视频:算法公开课-跟着Carl学算法

LeetCode 28 实现 strStr()

自己思路

KMP是第一次接触,不打算自己写,直接看讲解

看完讲解

关于KMP算法的讲解视频都看了两遍,除了卡哥的两集视频(理论篇+代码篇)之外,还推荐一个视频,这个视频有动画:最浅显易懂的 KMP 算法讲解,感觉三个视频结合一起看可以更好的加深理解,也正是这个动画视频我才看懂了为什么可以根据next回退去匹配,但是关于求next的时候为什么也可以这样回退,只能说知道了流程,但不懂为什么可以这样做,不过一刷了解到这我觉得够了

代码打算直接看着答案写了,应该就是上面的KMP算法的应用和复现,采用前缀表(不减一)的方法,所有的分析都写在注解当中了

class Solution {
    public int strStr(String haystack, String needle) {
        // 如果needle是空字符串直接返回0
        if (needle.length() == 0) {
            return 0;
        }
        int[] next = new int[needle.length()];
        // 获取next数组
        getNext(next, needle);

        // j:next数组的索引,needle的索引
        int j = 0;
        // i:haystack的索引
        for (int i = 0; i < haystack.length(); i++) {
            // 如果不相等就一直回退
            while ((j > 0) && (haystack.charAt(i) != needle.charAt(j))) {
                j = next[j - 1];
            }
            // 如果相等j前进一位,即比较下一位
            if (haystack.charAt(i) == needle.charAt(j)) {
                j++;
            }
            // 比较到j的最后一位表示找到
            if (j == needle.length()) {
                return i - needle.length() + 1;
            }
        }
        return -1;
    }

    // 获取next数组
    private void getNext(int[] next, String s) {
        // j: 前缀末尾,也是i及i之前的子串 的最长相等前后缀的长度
        // i: 后缀末尾
        int j = 0;
        next[0] = 0;
        for (int i = 1; i < s.length(); i++) {
            // 如果不相等就一直回退
            while ((j > 0) && (s.charAt(i) != s.charAt(j))) {
                j = next[j - 1];
            }
            // 如果相等j前进一位
            if (s.charAt(i) == s.charAt(j)) {
                j++;
            }
            // 更新next数组
            next[i] = j;
        }
    }
}

LeetCode 459 重复的子字符串

自己思路

KMP是第一次接触,不打算自己写,直接看讲解

看完讲解

这道题还是采用KMP算法,主要难点在于理解破题点:即当一个字符串由重复子串组成的,那么该重复子串就是整个字符串中最长相等前后缀所不包含的子串,具体推理过程可以看代码随想录的图,主要概括就是s01=t01=k01=s23、s23=t23=k23=s45、s45=t45=k45=s67,那么连起来就是s01=s23=s45=s67,所以最长相等前后缀所不包含的s01就是重复子串

代码还是直接看着答案写了,还是采用前缀表(不减一)的方法,代码随想录给的Java代码不是不减一的,只能对着C++的参考,还是所有的分析都写在注解当中了

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        // 如果s是空字符串直接返回false
        if (s.equals("")) {
            return false;
        }
        int[] next = new int[s.length()];
        // 获取next数组
        getNext(next, s);
        // 记录next数组长度,
        int len = s.length();
        // next[len - 1]: 最长相等前后缀,为0说明没有重复子串,也肯定不能被某子串重构
        // len - next[len - 1]: 重复子串,可以被len除尽说明可以被子串重复多次构成
        if ((next[len - 1] != 0) && (len % (len - next[len - 1]) == 0)) {
            return true;
        }
        return false;
    }

    // 获取next数组
    private void getNext(int[] next, String s) {
        // j:前缀末尾,也是i及i之前的子串 的最长相等前后缀的长度
        // i: 后缀末尾
        int j = 0;
        next[0] = 0;
        for (int i = 1; i < s.length(); i++) {
            // 如果不相等就一直回退
            while ((j > 0) && (s.charAt(i) != s.charAt(j))) {
                j = next[j - 1];
            }
            // 如果相等j前进一位
            if (s.charAt(i) == s.charAt(j)) {
                j++;
            }
            // 更新next数组
            next[i] = j;
        }
    }
}

总结

用时:3.5h,KMP算法很难,第一次接触

白天还解决了昨天留下的不懂151. 翻转字符串里的单词的问题,下午对于KMP算法的理解应该有了67成左右,足矣。发现在不懂的时候,反复看视频或者自己画图画出整个过程来会加快理解

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值