有缺陷的解决方案
不幸的是,thkang提供的解决方案以及unutbu修改后的版本在一些简单的输入情况下会失败。
例如,对于列表[1, 2, 1]
和[1, 1, 2]
,我们(正确地)得到了一个整数结果:
>>> is_shifted_copy([1, 2, 1], [1, 1, 2])
2
然而,当交换参数时,我们得到了(不正确的)结果
False
:
>>> is_shifted_copy([1, 1, 2], [1, 2, 1])
False
同样,其他被移位复制的列表也无法正确处理:
>>> is_shifted_copy([1, 2, 2], [2, 1, 2])
False
>>> is_shifted_copy([1, 1, 2, 1], [1, 2, 1, 1])
False
>>> is_shifted_copy([1, 2, 1, 3, 3], [3, 1, 2, 1, 3])
False
为了理解这个问题的源头,让我重现一下thkang解决方案的当前版本(使用Python 3的修改调用
next
)。
import itertools
def is_shifted_copy(list1, list2):
if len(list1) != len(list2):
return False
iterator = iter(list2)
for i, item in enumerate(itertools.chain(list1, list1)):
try:
if item == next(iterator):
continue
else:
iterator = iter(list2)
except StopIteration:
return i - len(list2)
else:
return False
现在,对于像is_shifted_copy([1, 2, 2], [2, 1, 2])
这样的调用,会发生以下情况:
i |
item |
next(iterator) |
结果 |
0 |
1 |
2^ |
重置迭代器 |
1 |
2 |
2^ |
继续循环 |
2 |
2 |
1 |
重置迭代器 |
3 |
1 |
2^ |
重置迭代器 |
4 |
2 |
2^ |
继续循环 |
5 |
2 |
1 |
重置迭代器,返回False |
返回list2
的第一个元素。
正如我们所看到的,输入列表中重复的元素导致迭代器itertools.chain(list1, list1)
在我们甚至没有机会到达list2
的最后一个元素之前就被耗尽了。
可能的解决方法
如果我们坚持使用迭代器(例如为了防止复制潜在的大型输入列表),我们必须确保第一个列表的迭代器在我们可以与第二个列表的元素进行比较之前不会被耗尽。我目前唯一能想到的保证第一个迭代器不被耗尽的方法是创建所有可能的list1
移位版本的新迭代器:
import itertools
def is_shifted_copy(list1, list2):
length = len(list1)
if len(list2) != length:
return
for i in range(length):
iterator1 = itertools.islice(itertools.cycle(list1), i, i + length + 1)
iterator2 = iter(list2)
for item in iterator1:
try:
if item != next(iterator2):
break
except StopIteration:
return -i % length
return None
>>> is_shifted_copy([1, 2, 3], [1, 2, 3])
0
>>> is_shifted_copy([1, 2, 3], [3, 1, 2])
1
>>> is_shifted_copy([1, 2, 3], [2, 3, 1])
2
>>> is_shifted_copy([1, 2, 3], [3, 2, 1])
None
>>> is_shifted_copy([1, 2, 3], [1])
None
>>> is_shifted_copy([1, 1, 2], [2, 1, 1])
1
>>> is_shifted_copy([1, 2, 1], [1, 1, 2])
1
>>> is_shifted_copy([1, 1, 2], [1, 2, 1])
2
>>> is_shifted_copy([1, 2, 2], [2, 1, 2])
1
>>> is_shifted_copy([1, 1, 2, 1], [1, 2, 1, 1])
3
>>> is_shifted_copy([1, 2, 1, 3, 3], [3, 1, 2, 1, 3])
1
最好的情况下,上述算法在O(n)
步骤内完成。对于大部分元素重复的输入列表,该算法的最坏情况是O(n^2)
。