我必须创建一个接受字符串的函数,并且该函数应该返回true或false基于输入是否包含重复的字符序列。给定字符串的长度始终大于,1并且字符序列必须至少重复一次。
true
false
1
"aa" // true(entirely contains two strings "a") "aaa" //true(entirely contains three string "a") "abcabcabc" //true(entirely containas three strings "abc") "aba" //false(At least there should be two same substrings and nothing more) "ababa" //false("ab" exists twice but "a" is extra so false)
我创建了以下功能:
function check(str){ if(!(str.length && str.length - 1)) return false; let temp = ''; for(let i = 0;i<=str.length/2;i++){ temp += str[i] //console.log(str.replace(new RegExp(temp,"g"),'')) if(!str.replace(new RegExp(temp,"g"),'')) return true; } return false; } console.log(check('aa')) //true console.log(check('aaa')) //true console.log(check('abcabcabc')) //true console.log(check('aba')) //false console.log(check('ababa')) //false
对此进行检查是真正问题的一部分。我负担不起这样的无效解决方案。首先,它遍历字符串的一半。
第二个问题是它replace()在每个循环中使用,这使其运行缓慢。关于性能,是否有更好的解决方案?
replace()
关于这样的字符串,有一个漂亮的小定理。
当且仅当字符串本身是非平凡的旋转时,字符串才由重复多次的相同模式组成。
在这里,旋转意味着从字符串的开头删除一些字符并将它们移到后面。例如,hello可以旋转字符串以形成以下任何字符串:
hello
hello (the trivial rotation) elloh llohe lohel ohell
为了了解其工作原理,首先,假设一个字符串包含k个字符串w的k个重复副本。然后从字符串的开头删除重复图案(w)的第一个副本,然后将其粘贴到背面,将得到相同的字符串。相反的方向很难证明,但是其想法是,如果旋转字符串并返回开始的位置,则可以重复应用该旋转,以用相同模式的多个副本平铺字符串(该模式是您需要移至末尾进行旋转的字符串)。
现在的问题是如何检查是否是这种情况。为此,我们可以使用另一个漂亮的定理:
如果x和y是相同长度的字符串,则当且仅当x是yy的子字符串时,x是y的旋转。
作为示例,我们可以看到这lohel是hello如下的轮换:
lohel
hellohello ^^^^^
在我们的例子中,我们知道每个字符串x始终是xx的子字符串(它将出现两次,在x的每个副本处出现一次)。因此,基本上我们只需要检查字符串x是否是xx的子字符串,而不允许它与第一个字符或中途字符匹配。这是一线的:
function check(str) { return (str + str).indexOf(str, 1) !== str.length; }
假设indexOf使用快速字符串匹配算法来实现,它将在时间O(n)中运行,其中n是输入字符串的长度。
indexOf
希望这可以帮助!