给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
示例 1:
- 输入: "abab"
- 输出: True
- 解释: 可由子字符串 "ab" 重复两次构成。
示例 2:
- 输入: "aba"
- 输出: False
示例 3:
- 输入: "abcabcabcabc"
- 输出: True
- 解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)
解法:KMP算法
如果一个字符串可以由重复子串构成,那么这个子串 是 它的最长相等前后缀 不包含的部分
例子:ababab,最长相等前后缀是abab,不包含ab,那么重复子串(如果有的话)是ab。
证明过程:
代码:
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
if len(s) == 0:
return False
nxt = [0] * len(s)
self.getNext(nxt,s)
if nxt[-1] != 0 and len(s) % (len(s)-nxt[-1]) == 0:
return True
return False
def getNext(self, nxt, s):
nxt[0] = 0
j = 0
for i in range(1, len(s)):
while j>0 and s[i] != s[j]:
j=nxt[j-1]
if s[i] == s[j]:
j += 1
nxt[i] = j
return nxt
注意:
在找nxt数组的时候,i从1开始,而不是从0开始。
是比较s中的元素是否相同,而不是nxt中的。
总结:
这道题思路比较巧妙。
KMP算法还需要多看,多练习,去熟练。
5月13日 重写:
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
if len(s)==0:
return False
nxt=[0]*len(s)
self.getNext(nxt,s)
if s[-1]!=0 and len(s)%(len(s)-s[-1])==0:
return True
return False
def getNext(self, nxt, s):
j=0
nxt[0]=j
for i in range(1,len(s)):
while j>=0 and s[i]!=s[j]:
j=nxt[j-1]
if s[i]==s[j]:
j+=1
nxt[i] = j
return nxt
错误点:
上面那个function是if nxt[-1]!=0, 而不是if s[-1]!=0. 是看next数组的最后一个元素。
同理,下面也是 len(s)-nxt[-1],而不是len(s)-s[-1]
主要是把s和nxt数组搞混了。nxt数组是记录最长相等前后缀的数组,s是字符串。
还有,这个题里面的next数组是没有-1的版本,所以while是while j>0,而不是j>=0.
当j=0的时候,且s[i]!=s[j], 那么next[i]就一直等于j,也就是等于0. 直到有s[i]==s[j],j才+1,等于1.
while j>0是为了保证下面 回退的时候,用到的j=nxt[j-1]是可以实现的,如果j=0,那么没有nxt[j-1],就会出现问题。