KMP算法
非常完整的思路https://www.programmercarl.com/0028.%E5%AE%9E%E7%8E%B0strStr.html#%E6%80%9D%E8%B7%AF
三位学者发明的:Knuth,Morris和Pratt,所以取了三位学者名字的首字母。所以叫做KMP
用途
KMP主要应用在字符串匹配上。
KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。
所以如何记录已经匹配的文本内容,是KMP的重点,也是next数组肩负的重任。
为什么要用前缀表
什么是前后缀
前缀 是指不包含最后一个字符的所有以第一个字符开头的连续子串;
后缀 是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
最长相等前后缀
首先要了解文本字符串和模式字符串,前者是题目中提到的haystack,后者是needle。eg:’aabaabaaf’,’aabaaf’
前缀表可以告诉我们应该跳转到哪里继续匹配。而不是从模式字符串的头部重新开始匹配。
为什么到下表为5时b!=f,可以直接将模式字符串下标调整到2呢。因为最长前后缀相等。
next实现过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const getNext = (nextArr, s ) => { let j = 0 nextArr[0 ] = 0 for (let i = 1 ; i < s.length ; i++) { while (s[i] != s[j] && j > 0 ) { j = nextArr[j - 1 ] } if (s[i] == s[j]) { j++ } nextArr[i] = j } return nextArr }
使用next前缀表实现字符串匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 var strStr = function (haystack, needle ) { const getNext = (nextArr, s ) => { let j = 0 nextArr[0 ] = 0 for (let i = 1 ; i < s.length ; i++) { while (s[i] != s[j] && j > 0 ) { j = nextArr[j - 1 ] } if (s[i] == s[j]) { j++ } nextArr[i] = j } return nextArr } let Arr = new Array (needle.length ) let nextArr = getNext (Arr ,needle) let j=0 for (let i=0 ;i<haystack.length ;i++){ while (j>0 && j<needle.length && haystack[i] != needle[j]){ j=nextArr[j-1 ] } if (haystack[i] == needle[j]){ j++ } if ( j == needle.length ){ return i-j+1 } } return -1 }
重复的子字符串
https://leetcode.cn/problems/repeated-substring-pattern/description/
思路1
s+s去掉头和尾,如果s还能出现在其中说明符合题目要求。
1 2 3 4 5 6 7 8 9 10 var repeatedSubstringPattern = function (s ) { let ss = s + s ss = ss.slice (1 , ss.length ) ss = ss.slice (0 , ss.length - 1 ) if (ss.includes (s)) { return true } else { return false } }
思路2
kmp算法,s.length - 最长相等前后缀,表示重复字符串的长度。
如果能被s.length整除,说明符合条件。
当然如果最长相等前后缀为0,纳智捷说明不符合要求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 var repeatedSubstringPattern = function (s ) { let nextArr = new Array (s.length ) nextArr[0 ] = 0 let j = 0 for (let i = 1 ; i < s.length ; i++) { while (j > 0 && s[i] != s[j]) { j = nextArr[j - 1 ] } if (s[i] == s[j]) { j++ } nextArr[i] = j } if ( nextArr[nextArr.length - 1 ] != 0 && s.length % (s.length - nextArr[nextArr.length - 1 ]) === 0 ) { return true } else { return false } };