代码随想录算法训练营第九天 | 28. 实现 strStr()、459. 重复的子字符串

98 阅读3分钟

KMP算法

链接

理论篇

代码篇

文章篇

代码实现

function KMP(str:string):number[]{
  let next:number[]=[0]
  let j:number=0//前缀末尾位置
  //i是后缀末尾位置
  for(let i=1;i<str.length;i++){
    while(j>0&&str[i]!=str[j]) j=next[j-1]
    if(str[i]==str[j])j++
    next[i]=j
  }
  return next
}

28. 实现 strStr()

链接

题目链接

文章链接

第一想法

这道题应该是考虑KMP的,下面是直接调用的写法

function strStr(haystack: string, needle: string): number {
  return haystack.indexOf(needle)
};

看完文章后的想法

文章主要介绍了KMP的原理,下面是解决这个问题的代码:

function strStr(haystack: string, needle: string): number {
//对模板字符生产next数组
   const getNext:(str:string)=>number[]=(str:string)=>{
        let next:number[]=[0]
        let j:number=0
        for(let i=1;i<str.length;i++){
            while(j>0&&str[i]!=str[j]){
                j=next[j-1]
            }
            if(str[i]==str[j]) j++;
            next[i]=j
        }
        return next
   }
   if(needle=='') return 0
   let next:number[]=getNext(needle)
   let j=0
   //模板字符串与查询字符串进行对比  并通过next进行跳转
   for(let i=0;i<haystack.length;i++){
       while(j>0&&haystack[i]!=needle[j]) j=next[j-1];
       if(haystack[i]==needle[j]){
           if(j==needle.length-1) return i-needle.length+1;
           j++
       }
   }
   return -1
};

思考

看完文章后,对KMP算法有些懵懵懂懂的感觉,求next数组能理解,但是没有完全理解,因为不会运用到题目中,所以还是得多多练习,代码随想录的文章中讲的很不错。这篇文章应该要多次阅读。要理解KMP算法,首先要理解前缀和后缀以及如何生成前缀表。得多看。

459. 重复的子字符串

链接

题目链接

文章链接

第一想法

想法很简单,我遇到这种是否是重复串的题,一般将s拼接成str=s+s,之后再去除str的第一个字符和最后一个字符,之后再str字符中查询s,如果能查询到,则一定是重复子串

function repeatedSubstringPattern(s: string): boolean {
  let str:string=s+s
  let arr:string[]=str.split("")
  arr.pop()
  arr.shift()
  str=arr.join("")
  return str.includes(s)
};

看完文章后的想法

文章的移动匹配的想法和我的想法是一致的,但是后面的KMP解法是我没想到的,真的很奇妙,得多加琢磨,下面上代码(PS:是看完文章讲解和代码后才照猫画虎写出来的):

function repeatedSubstringPattern(s: string): boolean {
  const KMP=(str:string):number[]=>{
      let next:number[]=[0]
      let j:number=0
      for(let i=1;i<str.length;i++){
          while(j>0&&str[i]!=str[j]) j=next[j-1];
          if(str[i]===str[j]) j++;
          next[i]=j
      }
       return next
  }
  let next:number[]=KMP(s)
  if(next[s.length-1]!=0&&(s.length%(s.length-next[s.length-1])==0)) return  true;
  return false
};

思考

KMP的思路还是不太熟练,还是得看完文章后才能有点思路,在KMP算法中最重要的是理解前后缀,只要把前后缀完全理解则KMP算法就不是太难的。这道题的重点是最长相等前后缀,前缀不包括最后一个子串,后缀不包括第一个子串,如果s.length%(s.length减去最长前后缀的长度)等于0的话说明是重复子串。

今日总结

今天的任务主要是学习KMP算法,对于KMP的算法还是蒙蒙的,得多看。今日学习时长3小时