第四章 字符串part02
今日任务
●28. 实现 strStr()
●459.重复的子字符串
●字符串总结
●双指针回顾
详细布置
28. 实现 strStr() (本题可以跳过)
因为KMP算法很难,大家别奢求 一次就把kmp全理解了,大家刚学KMP一定会有各种各样的疑问,先留着,别期望立刻啃明白,第一遍了解大概思路,二刷的时候,再看KMP会 好懂很多。
或者说大家可以放弃一刷可以不看KMP,今天来回顾一下之前的算法题目就可以。
因为大家 算法能力还没到,细扣 很难的算法,会把自己绕进去,就算别人给解释,只会激发出更多的问题和疑惑。
所以大家先了解大体过程,知道这么回事, 等自己有 算法基础和思维了,在看多看几遍视频,慢慢就理解了。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0028.%E5%AE%9E%E7%8E%B0strStr.html
459.重复的子字符串 (本题可以跳过)
本题算是KMP算法的一个应用,不过 对KMP了解不够熟练的话,理解本题就难很多。
我的建议是 KMP和本题,一刷的时候 ,可以适当放过,了解怎么回事就行,二刷的时候再来硬啃
题目链接/文章讲解/视频讲解:https://programmercarl.com/0459.%E9%87%8D%E5%A4%8D%E7%9A%84%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2.html
字符串总结
比较简单,大家读一遍就行
题目链接/文章讲解:https://programmercarl.com/%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%80%BB%E7%BB%93.html
双指针回顾
此时我们已经做过10到双指针的题目了,来一起回顾一下,大家自己也总结一下双指针的心得
文章讲解:https://programmercarl.com/%E5%8F%8C%E6%8C%87%E9%92%88%E6%80%BB%E7%BB%93.html
day09
实现 strStr()
一刷难,直接看视频
KMP算法
时间复杂度O(m+n),KMP算法用来匹配子串是否存在;KMP的效果就在于模式串只会遍历一次,只往前走永不回退,不过中途可能等着needle跳来跳去的;精髓就在于前缀表
先搞懂不减一的next怎么生成的
//方法一:获取前缀表,next()不减一 //1.初始化 2.处理不相同的情况 3.处理相同的情况 4.next()赋值 private void getNext(int[] next, String s) { //1.初始化 //变量解释: //i,j是模式串needle的下标索引,i是后缀末尾下标,j是前缀末尾下标;next[i]表示i位置(包含i)的最大相等前后缀的长度 //变量初始化: //j初始化为0,从头开始;next[0]初始化为0,因为0索引处最大相等前后缀长度为0; int j = 0; next[0] = 0; //2.处理不同的情况 //i从1开始遍历,因为next[0]已经有了,而且ij都指向0索引处,最大相等前后缀的长度 也是0,没必要判断 for (int i = 1; i < s.length(); i++) { //当s.charAt(j) != s.charAt(i)的时候,说明最大相等前后缀已经找完了,前缀j要更新 //这里前缀j为什么要更新成next[j-1]呢?去看这个:从第五分钟开始看,看不懂我不信https://www.bilibili.com/video/BV1AY4y157yL/?spm_id_from=333.337.search-card.all.click&vd_source=a350af2b28053c72e1cca8bbb5bba644 while (j > 0 && s.charAt(j) != s.charAt(i)) //举例字符串ABADABAB,此时前缀j在ABAD的D,后缀i在ABAB的B,ij对应元素不相同了 //后缀i是不会回退的,i一直往后走,要更新前缀j然后继续往后匹配,对ABAD和ABAB,有共同的ABA,因为charAt(j-1)是1,可以从目前已匹配到的A和AB去找,j++,变成AB和AB更新next[i]为2. j = next[j - 1];//更新前缀为前缀本身作为字符串最大的前后缀,这样就可以继续往后匹配了 //3.处理相同的情况 //当s.charAt(j) == s.charAt(i)的时候,让j++,并且把已经+1的前缀j赋值给next[i] if (s.charAt(j) == s.charAt(i)) j++; //4.j已经加过了,赋值即可 next[i] = j; } }
//自己写一遍next() private void getNext( int[] next, String s){ //1.初始化 int j = 0; next[0] = 0; //2.不相等的情况 for(int i = 1; i < s.length(); i++) { while( j>0 &&s.charAt(i) != s.charAt(j)){ j = next[j-1];//会有j-1,加个j>0防止越界 } //3.相等的情况 //走到这里要么j=0,要么s.charAt(i)==s.charAt(j),先看相等的情况,j可以往后继续走了 if( s.charAt(i)==s.charAt(j)){ next[i] = j; j++; }else{//else就是j==0了 next[i] = 0; } //优化一下就是把一定会执行的 next[i] = j;放到外面,变成 // if (s.charAt(j) == s.charAt(i)) // j++; // next[i] = j; } }
//完整代码 class Solution { public int strStr(String haystack, String needle) { if( needle.length() == 0) return 0; //生成不减一的next() int len = needle.length(); int[] next = new int[len]; getNext( next, needle); //开始遍历haystack,i不会回退 int j = 0; for(int i = 0; i < haystack.length(); i++){ //如果不匹配,就让needle的下标j循环回退 while( j>0 && needle.charAt(j) != haystack.charAt(i)){ //这里是needle和stack比较!next里面是needle和needle比较! j = next[ j - 1]; } //要么j = 0,要么 == if( haystack.charAt(i) == needle.charAt(j)) j++;//做下一个字母比较的准备 if( j == len) return i - len + 1;//返回下标 } return -1;//没匹配成功 } private void getNext(int[] next, String s) { int j = 0; next[0] = 0; for (int i = 1; i < s.length(); i++) { while (j > 0 && s.charAt(j) != s.charAt(i)) j = next[j - 1]; if (s.charAt(j) == s.charAt(i)) j++; next[i] = j; } } }
终于搞明白了,花了本菜鸡两个半小时(菜哭)
重复的子字符串
一刷难,直接看视频
KMP算法
//主要是难在逻辑推理,算法实现非常简单,就是kmp套一个取模的壳子 class Solution { public boolean repeatedSubstringPattern(String s) { int len = s.length(); if(len < 2) return false; int[] next = new int[len]; getNext(next, s); if( len % ( len - next[ len - 1 ] ) ==0 ){ return true; } return false; } private void getNext(int[] next, String s) { int j = 0; next[0] = 0; for (int i = 1; i < s.length(); i++) { while (j > 0 && s.charAt(j) != s.charAt(i)) j = next[j - 1]; if (s.charAt(j) == s.charAt(i)) j++; next[i] = j; } } } //一个取模操作直接秒了
字符串总结:代码随想录
双指针总结:代码随想录
看总结的时候发现好多题的细节都记不太清楚了,不过让我复习比杀了我还难受,直接继续往后了
注:感谢大佬分享