我们对二进制字符串的数据结构感兴趣。令S = s 1 s 2 .... s m 是大小为m
的二进制字符串。 Shift(S,i)
是字符串S
i
空格的循环移位到左侧。也就是说,Shift(S,i)= s i s i + 1 s i + 2 ... s m < /子>取值<子> 1 子>内容S <子> I-1 子>。建议支持以下的高效数据结构:
Init()
Insert(s)
在O(| s | ^ 2)Search_cyclic(s)
检查O(| s |)中的任何Shift(S,i)
是否i
。空间复杂度:O(| S 1 | + | S 2 | + ..... + | S m |)其中S i 是一个,如果m字符串我们已经插入了这么远。
如果我必须为某些给定i找到Search_cyclic(s,i),使用后缀树并在O(| s |)中遍历它非常简单。但是在Search_cyclic(s)中我们没有给定的i,因此我不知道在给定的复杂性中该怎么做。 OTOH,Insert(s)通常将O(| s |)插入到后缀树中,这里给出O(| s | ^ 2)。
答案 0 :(得分:0)
所以这是我可以向你提出的解决方案。复杂性甚至低于他们对你的要求,但看起来有点复杂。
您保留所有字符串的数据结构将是Trie甚至是Patricia tree。在每个字符串的树中,您希望在所有可能的移位中插入最小循环移位(即,所有可能的最小字典顺序移位)。您可以在线性时间内计算字符串的最小循环移位,稍后我将给出一个可能的解决方案。暂时让我们假设你可以做到。以下是如何实施所需的操作:
此外,内存复杂性也是必需的,如果构建Patricia,可能会更低。
所以剩下的就是如何找到最小的循环移位。既然你提到了后缀树,我希望你知道如何在linear time中构建它。所以诀窍是 - 你将你的字符串s附加到自身(即加倍),然后你为doubled字符串构造一个后缀树。这对于| s |仍然是线性的所以没问题。之后,您所要做的就是在此树中找到长度为n的最小后缀。我认为这并不难 - 从根开始并始终遵循当前节点上的链接,该节点上写有最小的字符串,直到累积的长度超过| s |。由于字符串加倍,您将始终能够遵循最小的字符串链接,直到您至少累积| s |。
希望这个答案有所帮助。