我有此功能,以确定一个列表是否是另一个列表的旋转:
def isRotation(a,b): if len(a) != len(b): return False c=b*2 i=0 while a[0] != c[i]: i+=1 for x in a: if x!= c[i]: return False i+=1 return True
例如
>>> a = [1,2,3] >>> b = [2,3,1] >>> isRotation(a, b) True
我该如何处理重复项?例如
a = [3,1,2,3,4] b = [3,4,3,1,2]
可以及时完成O(n)吗?
O(n)
您可以使用最大后缀算法的修改版在0(n)时间和0(1)空间上做到这一点:
0(n)
0(1)
摘自《弦论之珠宝》: 单词的循环相等
长度为n的单词u的旋转是形式为u [k +1 … n] [l … k]的任何单词。令u,w为两个相同长度n的单词。如果对于某些i,j u(i)== w(j),则称它们为循环等效的。 如果单词u和w被写为圆圈,则在适当的旋转之后如果圆圈重合,则它们在循环上等效。 有几种线性时间算法可以测试两个单词的循环等效性。最简单的方法是将任何字符串匹配算法应用于模式pat = u和text = ww,因为如果pat出现在文本中,则单词u和w循环=等效。 另一种算法是找到uu和ww的最大后缀,并检查它们在大小n的前缀上是否相同。我们之所以选择这个问题,是因为有一种更简单有趣的算法,它同时在线性时间和恒定空间中工作,值得介绍。
长度为n的单词u的旋转是形式为u [k +1 … n] [l … k]的任何单词。令u,w为两个相同长度n的单词。如果对于某些i,j u(i)== w(j),则称它们为循环等效的。
如果单词u和w被写为圆圈,则在适当的旋转之后如果圆圈重合,则它们在循环上等效。
有几种线性时间算法可以测试两个单词的循环等效性。最简单的方法是将任何字符串匹配算法应用于模式pat = u和text = ww,因为如果pat出现在文本中,则单词u和w循环=等效。
另一种算法是找到uu和ww的最大后缀,并检查它们在大小n的前缀上是否相同。我们之所以选择这个问题,是因为有一种更简单有趣的算法,它同时在线性时间和恒定空间中工作,值得介绍。
Algorithm Cyclic-Equivalence(u, w) { checks cyclic equality of u and w of common length n } 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; { invariant } 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 length is different we cannot get a match if len(l2) != len(l1): return False # if any elements are different we cannot get a match if set(l1).difference(l2): return False l2,l1 = deque(l2),deque(l1) for i in range(len(l1)): l2.rotate() # l2.appendleft(d.pop()) if l1 == l2: return True return False