如何解决以下问题:首先将字符串循环旋转1个字母,然后再旋转2个字母,然后很快旋转,那么什么时候修改后的字符串将等于原始字符串?这些字符串仅由'a'和'b'组成。
例如:aabaab是第一个字母旋转的字符串,它将在第二个旋转时变为abaaba,它将变为aabaab,因此答案为2。
我试图解决这个问题,但只能靠蛮力来解决。 https://pasteboard.co/HwWR6WZ.png
任何帮助将不胜感激。
答案 0 :(得分:1)
让s
是原始字符串,您想要的是最小的索引i > 0
,这样s
是字符串{{1}中索引i
的子字符串}。您可以构造ss
的{{3}},然后在此树中搜索ss
。该算法运行时间为O(n)。
例如,考虑s
,即s = abab
的后缀树,即ss
看起来像(abababab
代表字符串的结尾)
$
搜索 root
ab/ \b
/ \
ab/\$ $/\ab
/ \ / \
* 6 7 $/\ab
ab/\$ / \
/ \ 5 $/\ab$
ab$/\$ 4 / \
/ \ 3 1
0 2
后,我们到达abab
节点,并且在其子树中有三片叶子代表索引0、2、4。答案是其中最小的正指数,即2。
在O(n)时间内使用后缀数组和LCP数组的后缀树suffix tree。
答案 1 :(得分:0)
由于字符串仅包含'a'和'b',因此可以将它们表示为1和0 s的位。然后循环移位并执行XOR之类的按位操作可能会为您提供更好的性能。
答案 2 :(得分:-2)
我不知道您所说的蛮力是什么意思,但我会这样做:
它应该在线性时间内工作,它将是O(2*N)
的顶部。我已经通过clang's substring find进行了检查,它最多会通过搜索到的字符串(即循环一个)的大小。
由于该字符串已加倍,它将最多在s.size()
处找到一个匹配项。
#include <iostream>
#include <string>
using namespace std;
auto steps(const string& s) {
string cycled = s+s;
return cycled.find(s, 1);
}
int main() {
string s{"aabaab"};
cout << steps(s) << '\n';
return 0;
}
我想您可以通过避免复制并只对原始字符串进行处理来优化内存和一段时间,但是您需要提供一个自定义迭代器,该迭代器会遍历字符串。然后,应该可以相当容易地从std::basic_string
重写算法。