Lior 和 Jeffrey 的答案构成了解决问题的基础,但本文中还有一个有趣的问题有待解决,如何有效地计算给定 [input string, N, K] 的周期性字符串的数量。我的回答将主要集中在这一点上。
正如 Lior 和 Jeffrey 所指出的,在检查周期性字符串时,我们只需要关心长度等于 n 的除数的子字符串。让我们看一个例子,看看我们能如何高效地实现这一目标。
周期为 m 的周期字符串数
设输入字符串为
0110 0011 0101 0001
让我们尝试找出周期为 m=4 的周期字符串的数量
第一位
如果我们比较每个子字符串的第一位,我们会发现它们都是0s。如果我们假设在所有子字符串中所有后续位都相同,那么当执行 0 位翻转或 4 位翻转时,输入字符串可以是周期性的(周期为 4)。
0110 0011 0101 0001
^ ^ ^ ^
Number of 0s = 4
Number of 1s = 0
Number of bitflips to make all 0s to 1s = 4
Number of bitflips to make all 1s to 0s = 0
Number of periodic strings with period=4 for:
k = 0 => 1
k = 4 => 1
所以现在我们知道存在 2 个周期性字符串,一个用于 k=0,另一个用于 k=4(假设所有子字符串中的后续位都相同)。
第二位
现在让我们进入第二个部分。
0110 0011 0101 0001
^ ^ ^ ^
Number of 0s = 2
Number of 1s = 2
Number of bitflips to make all 0s to 1s = 2
Number of bitflips to make all 1s to 0s = 2
但是等等,上面的陈述是正确的,如果子字符串中当前位之前的所有位也有助于使字符串周期性。我们知道只有k=0 和k=4,每个都使字符串周期性地达到第一位。
所以当考虑到第 2 位之前的所有位时,我们可以在以下 4 种情况下得到一个周期性字符串:
When previousK = 0:
Flip the 2 `0`s to `1`s => new k = 2
Flip the 2 `1`s to `0`s => new k = 2
When previousK = 4:
Flip the 2 `0`s to `1`s => new k = 6
Flip the 2 `1`s to `0`s => new k = 6
Number of periodic strings with period=4 for:
k = 2 => 2
k = 6 => 2
第三位
转到第三位,我们将看到:
0110 0011 0101 0001
^ ^ ^ ^
Number of 0s = 2
Number of 1s = 2
Number of bitflips to make all 0s to 1s = 2
Number of bitflips to make all 1s to 0s = 2
We can get a periodic string in the following 4 cases:
When previousK = 2:
Flip the 2 `0`s to `1`s => new k = 4
Flip the 2 `1`s to `0`s => new k = 4
When previousK = 6:
Flip the 2 `0`s to `1`s => new k = 8
Flip the 2 `1`s to `0`s => new k = 8
Number of periodic strings with period=4 for:
k = 4 => 4
k = 8 => 4
第四位
对于我们的第四个也是最后一点:
0110 0011 0101 0001
^ ^ ^ ^
Number of 0s = 1
Number of 1s = 3
We can get a periodic string in the following 4 cases:
When previousK = 4:
Flip the 1 `0`s to `1`s => new k = 5
Flip the 3 `1`s to `0`s => new k = 7
When previousK = 8:
Flip the 1 `0`s to `1`s => new k = 9
Flip the 3 `1`s to `0`s => new k = 11
Number of periodic strings with period=4 for:
k = 5 => 4
k = 7 => 4
k = 9 => 4
k = 11 => 4
我们现在完成了子字符串的最后一位,最后一步中各种 k 值的周期字符串的总和为 16。
递归关系和伪代码
让我们使用 R[k] 表示任何 k 的周期字符串的当前计数,它从 1 到 K 不等。对于每次迭代,我们都需要查找上一次迭代的R[] 值。
我们在每次迭代中最终要做的事情是:
for offset = 0 to periodLen - 1
flip R[] and previousR[]
for currentK = 1 to K
R[currentK] = 0
numZeroes = 0
for (pos = offset; pos < n; pos += periodLen)
if (str[pos] == '0')
++numZeros
numOnes = (n / m) - numZeroes;
for currentK = 1 to K
if m == 0
R[currentK + numZeroes] = 1
R[currentK + numOnes] = 1
else if (previousR[currentK] > 0)
R[currrentK + numZeroes] += previousR[currentK]
R[currentK + numOnes] += previousR[currentK]
totalPeriodicCount = 0
for currentK = 1 to K
totalPeriodicCount += R[currentK]
如果我们通过从最低到最高迭代所有周期来执行上述过程,我们将获得所有周期字符串的计数。将选择的周期将是N 的除数,它们小于N。将它们从低到高遍历会有优势,请阅读下一节了解详细信息。
计算可被较小期间整除的期间
仔细观察,您会发现我们还不止一次地计算某些周期性字符串。
例如。以下周期性字符串:
0001 0001 0001 0001
最终将被计算为 m = 4 和 m = 8 的一部分
让C[m] 表示使用上述伪代码获得的一段长度为m 的周期字符串的总数。令C[m'] 表示使用长度为m 的周期获得的周期字符串的实际计数,但不计算可以使用periods < m 形成的周期字符串
更具体地说,如果当前周期 m 的除数 t、u 和 v 小于 m,那么我们将计算周期字符串的数量 t , u 和 v 也一样,即
C[m] = C[t'] + C[u'] + C[v'] + C[m']
在计算所有m值的周期字符串总数时,我们需要注意排除C[t]、C[u]和C[v],只考虑C[m']。
由于我们在计算C[m] 时,我们已经计算了C[t']、C[u'] 和C[v'] 的值,我们只需查找它们并从C[m] 中减去它们即可得到@ 987654362@。我将把这个简单的部分作为练习留给读者。
C[m'] = C[m] - C[t'] - C[u'] - C[v']