通过修改最大后缀算法的版本,可以在0(n)
时间和0(1)
空间内完成:
引自《串的珠宝》:
循环等价性
长度为n的单词u的旋转是形式为u[k+1...n][l...k]的任意单词。令u、w为长度相同的两个单词,如果存在i、j使得u(i) == w(j),则它们被称为循环等价。
如果将单词u和w写成圆,当圆在适当的旋转后重合时,它们是循环等价的。
有几种线性时间算法可用于测试两个单词的循环等价性。最简单的方法是将任何字符串匹配算法应用于模式pat = u和文本text = ww,因为如果pat出现在text中,则单词u和w是循环等价的。
另一种算法是找到uu和ww的最大后缀,并检查它们在大小为n的前缀上是否相同。我们选择这个问题,因为有一个更简单的有趣算法,同时在线性时间和常量空间中工作,值得介绍。
Algorithm Cyclic-Equivalence(u, w)
x := uu; y := ww;
i := 0; j := 0;
while (i < n) and (j < n) do begin
k := 1;
while x[i + k] = y[j + k] do k := k + 1;
if k > n then return true;
if x[i + k]> y[i + k] then i := i + k else j := j + k;
end;
return false;
翻译成Python后变成:
def cyclic_equiv(u, v):
n, i, j = len(u), 0, 0
if n != len(v):
return False
while i < n and j < n:
k = 1
while k <= n and u[(i + k) % n] == v[(j + k) % n]:
k += 1
if k > n:
return True
if u[(i + k) % n] > v[(j + k) % n]:
i += k
else:
j += k
return False
运行一些示例:
In [4]: a = [3,1,2,3,4]
In [5]: b =[3,4,3,1,2]
In [6]: cyclic_equiv(a,b)
Out[6]: True
In [7]: b =[3,4,3,2,1]
In [8]: cyclic_equiv(a,b)
Out[8]: False
In [9]: b =[3,4,3,2]
In [10]: cyclic_equiv(a,b)
Out[10]: False
In [11]: cyclic_equiv([1,2,3],[1,2,3])
Out[11]: True
In [12]: cyclic_equiv([3,1,2],[1,2,3])
Out[12]: True
一种更加天真的方法是使用collections.deque来旋转元素:
def rot(l1,l2):
from collections import deque
if l1 == l2:
return True
if len(l2) != len(l1):
return False
if set(l1).difference(l2):
return False
l2,l1 = deque(l2),deque(l1)
for i in range(len(l1)):
l2.rotate()
if l1 == l2:
return True
return False