算法训练营day09(字符串02:KMP算法,strStr()查子串,重复的子串,字符串总结,双指针总结)

第四章 字符串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; 
         }
     }
 }
 //一个取模操作直接秒了

字符串总结:代码随想录

双指针总结:代码随想录

看总结的时候发现好多题的细节都记不太清楚了,不过让我复习比杀了我还难受,直接继续往后了

注:感谢大佬分享

代码随想录-算法训练营day09【字符串02:KMP、重复的子字符串、字符串总结、双指针回顾】-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值