持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情
一、题目描述:
给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。
示例 1:
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。
示例 2:
输入: s = "aba"
输出: false
示例 3:
输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)
提示:
- 1 <= s.length <= 10^4
- s 由小写英文字母组成
二、思路分析:
通过KMP算法计算出前后缀完全相等的长度max_size,由len(s)-max_size即可得出最短重复子串,再通过len(s)%max_size判断len(s)是否是max_size的倍数,以保证子串的完整性。
假设原字符串s为ababab,此时KMP计算得出前缀表为[0,0,1,2,3,4],此时最长前缀f为前abab,最长后缀l为后abab,s-l=ab(s[0:2]),又因为f[0]=l[0]、f[1]=l[1],带入原字符串下标可得s[0:2] = s[2:4],所以ab(s[0:2])即为最短重复子字符串,只需通过len(s)%len(ab)=>len(s) % (len(s)-len(l))判断字符串是否都是由最短重复子字符串构成即可。
三、AC 代码:
func KMP(s string)bool{
// 变量初始化
i, n := 0, len(s)
// 初始化前缀吧
next := make([]int, len(s))
for j := 1; j < len(s); j++{
// 如果慢指针i不等于0且s[i]不等于s[j]
for i > 0 && s[i] != s[j]{
// 跳到上一个相等前后缀位置
i = next[i-1]
}
// 如果快慢指针值相等,则慢指针移动一位代表相等前缀后缀长度+1
if s[i] == s[j]{
i += 1
}
// 更新next数组当前位置的相等前缀后缀长度
next[j] = i
}
// 如果最长相等前缀后缀长度为0则说明不是由特定子字符串重复构建
//如果非0则判断原字符串长度是否是最短重复子字符串长度的倍数
//借此来判断原字符串是否全部由最短重复子字符串构成
return next[n-1] != 0 && n % (n - next[n-1]) == 0
}
func repeatedSubstringPattern(s string) bool {
// 返回结果
return KMP(s)
}