一尘不染

如何检查字符串是否完全由相同的子字符串组成?

algorithm

我必须创建一个接受字符串的函数,并且该函数应该返回truefalse基于输入是否包含重复的字符序列。给定字符串的长度始终大于,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()在每个循环中使用,这使其运行缓慢。关于性能,是否有更好的解决方案?


阅读 338

收藏
2020-07-28

共1个答案

一尘不染

关于这样的字符串,有一个漂亮的小定理。

当且仅当字符串本身是非平凡的旋转时,字符串才由重复多次的相同模式组成。

在这里,旋转意味着从字符串的开头删除一些字符并将它们移到后面。例如,hello可以旋转字符串以形成以下任何字符串:

hello (the trivial rotation)
elloh 
llohe 
lohel 
ohell

为了了解其工作原理,首先,假设一个字符串包含k个字符串w的k个重复副本。然后从字符串的开头删除重复图案(w)的第一个副本,然后将其粘贴到背面,将得到相同的字符串。相反的方向很难证明,但是其想法是,如果旋转字符串并返回开始的位置,则可以重复应用该旋转,以用相同模式的多个副本平铺字符串(该模式是您需要移至末尾进行旋转的字符串)。

现在的问题是如何检查是否是这种情况。为此,我们可以使用另一个漂亮的定理:

如果x和y是相同长度的字符串,则当且仅当x是yy的子字符串时,x是y的旋转。

作为示例,我们可以看到这lohelhello如下的轮换:

hellohello
   ^^^^^

在我们的例子中,我们知道每个字符串x始终是xx的子字符串(它将出现两次,在x的每个副本处出现一次)。因此,基本上我们只需要检查字符串x是否是xx的子字符串,而不允许它与第一个字符或中途字符匹配。这是一线的:

function check(str) {
    return (str + str).indexOf(str, 1) !== str.length;
}

假设indexOf使用快速字符串匹配算法来实现,它将在时间O(n)中运行,其中n是输入字符串的长度。

希望这可以帮助!

2020-07-28