确定两个阵列是否是彼此的旋转版本



JAVA中也有人问过类似的问题,但有人能帮助我改进代码吗?并解释我的代码的时间复杂性和空间复杂性。我的代码检查两个数组是否是彼此的旋转版本:

list1=[1,2,3,4,5,6,7]

list2b=[4,5,6,7,1,2,3]

is_rrotation(list1,list2b(应返回True。

list2c=[4,5,6,9,1,2,3]

is_rrotation(list1,list2c(应返回False。

我的代码:

def is_rotation (list1,list2):
i = 0
j = 0
k = 0
result = True
if len(list1) != len(list2):
return False  
while i < len(list1) -1 and j < len(list1) -1:
if list1[i] == list2[j]:
i = i +1
j = j +1
break
elif list1[i] > list2[j]:
j = j +1
else:
i = i +1
else:
return False
for l in range(i,len(list1)):
if i == j:
if list1[i] != list2[j]: 
return False
elif list1[i] != list2[j] or list2[i] != list1[k]:
return False
else:
i = i +1
j = j +1
k = k +1
return result

一种有点技巧的方法:

def is_rotation(lst1, lst2):
if(len(lst1)==len(lst2)):
return (str(lst1)[1:-1] in str(lst2+lst2)) & (str(lst2)[1:-1] in str(lst1+lst1)) 
else:
return False

它是如何工作的:

(1( 检查两个列表的长度是否相同,如果不返回False

(2( 如果他们这样做了,将第一个列表转换为string,去掉最外面的括号(通过去掉第一个和最后一个字符——你可以在那里做任何括号,而不仅仅是方形括号,它也可以是tuple(。

(3(lst2+lst2将返回按顺序重复的lst2的所有元素(因此一个lst2接一个(。然后转换为字符串,它将只返回list的字符串格式

(4( 根据评论-为了处理拐角情况-我们应该双向检查,因为如果lst1lst2的旋转版本,那么lst2lst1的旋转版本

测试

print(is_rotation([561, 1, 1, 1, 135], [1, 1, 1, 1, 1]))
#outputs False
print(is_rotation([[1,2,3,4], 2, 3, 4], [1, 2,3,4]))
#outputs False
print(is_rotation([1, 2, 3, 4, 5], [4, 5, 1, 2, 3]))
#outputs True

对于更明确的方法,您可以使用itertools逐个生成给定列表的所有旋转,如下所示:

import itertools as it
def get_rotations(lst1):
foo = it.cycle(lst1)
for y in range(len(lst1)):
result = []
for x in range(len(lst1)):
result.append(next(foo))
yield result
next foo

然后你可以做:

def is_rotated(L1, L2) -> bool:
bar = get_rotations(L1)
While True:
try:
if next(bar) == L2;
return True
except StopIteration:
return False

旁白:我认为这打破了所有关于使用异常来控制程序逻辑正常流程的传统观点,然而。。。不知怎么的,这感觉不对(在C++的背景下,我们被反复告知永远不要做这种事情。(。这是Python吗?

您可以使用来自itertools的cycle来优化比较数量,避免创建额外的数据副本。(即O(n(时间中的O(1(空间(

以下是一个函数示例,如果两个列表是彼此的旋转,则该函数将返回旋转偏移;如果不匹配,则返回None。该逻辑永远不需要超过2N个比较来确定偏移。

from itertools import cycle
def getRotation(listA,listB):
if len(listA) != len(listB): return None
unmatched,offset = len(listA),0
iterA,iterB      = cycle(listA),cycle(listB)
a = next(iterA)
while unmatched and offset<len(listA):
b = next(iterB)
if a==b:
unmatched -= 1
a = next(iterA)
else:
unmatched = len(listA)
offset   += 1
if unmatched: return None
return offset

输出:

list1 = [1, 2, 3, 4, 5, 6, 7]
list2b = [4, 5, 6, 7, 1, 2, 3]
print(getRotation(list1,list2b)) # 4 (rotation to the right)

如果需要,您可以调整它以简单地返回True或False。

它还可以很容易地用于检查是否可以通过循环生成列表。(例如[2,3,1,2,3,1,2,1,2,1.2]可以通过循环[1,2,3]产生(为了避免混淆问题,我没有在示例中包含该功能

我想用另一种方法来做到这一点:

def is_rotation (list1,list2):
if len(list1) != len(list2):
return False
for i in range(len(list1)):
if list1[i:] + list1[:i] == list2:
return True
return False

1( 测试两者是否具有相同的长度。

2( 循环只会旋转列表中的所有可能性,并检查其中一个可能性是否相等。。

我不知道这是否是最好的方法,但很容易理解;(

最新更新