题目:
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过 10000。
示例
- 示例 1:
输入: "abab"
输出: True
解释: 可由子字符串 "ab" 重复两次构成。
- 示例 2:
输入: [1, 2, 1, 2]
输出: False
- 示例 3:
输入: "abcabcabcabc"
输出: True
解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)
抛砖引玉
暴力校验
思路
从开始枚举字符串片段假设其满足,继续向后枚举校验,检验完成未遇到不满足则返回 true,不然返回 false
a | b | c | a | b | c |
---|---|---|---|---|---|
i | i+1 | i+2 | i+3 | i+4 | i+5 |
- | j | j+1 | j+2 | j+3 | j+4 |
… | … | … | … | … | … |
… | … | … | j | j+1 | j+2 |
前置条件:指定相同量字符之间的长度应该满足被 n 整除
/**
* @param {string} s
* @return {boolean}
*/
var repeatedSubstringPattern = function (s) {
let len = s.length
for (let i = 1; i * 2 <= len; ++i) {
if (len % i == 0) {
let match = true
for (let j = i; j < len; ++j) {
if (s[j] != s[j - i]) {
match = false
break
}
}
if (match) {
return true
}
}
}
return false
}
字符串匹配
字符串拼接一次自身,然后删除拼接后的字符串的开始和结束:
- 如果字符串满足可以被子集重复得到,那么至少当前处理过的字符还包含原字符串 s
/**
* @param {string} s
* @return {boolean}
*/
var repeatedSubstringPattern = function (s) {
return (s + s).slice(1, -1).includes(s)
}
正则
一般字符串匹配的问题都可以通过正则处理:
- 匹配一个字符串组 w+,匹配其大于 1 次
/**
* @param {string} s
* @return {boolean}
*/
var repeatedSubstringPattern = function (s) {
return /^(\w+)\1+$/.test(s)
}
KMP 算法
逻辑
- KMP 算法分为模式串和匹配串
- 先遍历模式串,记录模式串中,每个指针前的最长公共前缀
- 当模式串与匹配串匹配时,某个位置不匹配时,
- 直接将模式串的后移该指针位置的公共前缀的长度在再与匹配串该位置比较
- 模式串已匹配的前缀字符无需再次匹配
/**
* @param {string} s
* @return {boolean}
*/
var repeatedSubstringPattern = function (s) {
function kmp(query, pattern) {
let n = query.length,
m = pattern.length,
fail = Array(m).fill(-1)
// 最长公共前缀,不存在公共前缀填充-1
for (let i = 1; i < m; ++i) {
let j = fail[i - 1]
while (j != -1 && pattern[j + 1] != pattern[i]) {
j = fail[j]
}
if (pattern[j + 1] == pattern[i]) {
fail[i] = j + 1
}
}
// 校验 match记录匹配的位置
let match = -1
for (let i = 1; i < n - 1; ++i) {
// 如果当前不匹配匹配,指针跳跃到前缀位置开始匹配
while (match != -1 && pattern[match + 1] != query[i]) {
match = fail[match]
}
// 如果当前位匹配,逐个向后匹配,知道模式串匹配完成
if (pattern[match + 1] == query[i]) {
++match
if (match == m - 1) {
return true
}
}
}
// 与字符串方法类似,拼接两个s,且将单个s作为模式串匹配去掉首尾字符非拼接串
return kmp(s + s, s)
}
}
博客: 小书童博客
每天的每日一题,写的题解会同步更新到公众号一天一大 lee 栏目
欢迎关注留言
公号: 坑人的小书童