Day9
前言
来到了所谓的KMP算法,全新的未知领域
文章:代码随想录
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成左右,足矣。发现在不懂的时候,反复看视频或者自己画图画出整个过程来会加快理解