如果可以通过交换其中一个列表中的最多一对元素来从另一个列表中获得一个列表,则将两个列表称为相似列表。我解决了这个问题,但是我需要让它在4秒内针对所有输入运行(Python3)。有什么想法可以提高效率吗?
def areSimilar (a,b):
counter=0
for i in range(len(a)):
for j in range(len(b)):
if counter < 1 and a[i]!=b[i]:
if a[i]==b[j]:
temp=b[j]
b[j]=b[i]
b[i]=temp
counter+=1
else:
flag=False
if a == b:
flag=True
else:
flag = False
return flag
a= [832, 998, 148, 570, 533, 561, 894, 147, 455, 279]
b= [832, 998, 148, 570, 533, 561, 455, 147, 894, 279]
p=areSimilar(a,b)
我认为嵌套循环是我的问题。
答案 0 :(得分:4)
是的,您的逻辑非常缓慢。没有理由使用嵌套循环:您已经将 O(N)问题变成了 O(N ^ 2)程序。
首先,只有长度相同的列表才能相似。一旦检查完,就遍历配对列表一次,注意元素不匹配的位置。如果您发现第三个不匹配,则它们不相似。如果您一次不匹配就结束了,那就不一样了。如果发现0个不匹配项,则它们相似。
唯一困难更大的情况是,如果您发现恰好两个元素不匹配的位置。分别命名为i
和j
。此时,只需检查是否为a[i] == b[j] and a[j] == b[i]
。返回比较结果。
请注意,在此过程中无处实际上会交换元素。您无需使列表完全相同,只需确定交换是0还是1的可能。
答案 1 :(得分:3)
通过两个列表的简单迭代来计算差异数量即可。
import operator
from itertools import zip_longest
def areSimilar(a, b):
if a == b:
return True
diff = list(filter(lambda t: operator.ne(*t), zip_longest(a, b)))
return len(diff) == 2 and diff[0] == diff[1][::-1]
a= [832, 998, 148, 570, 533, 561, 894, 147, 455, 279]
b= [832, 998, 148, 570, 533, 561, 455, 147, 894, 279]
print(areSimilar(a, b))
print(areSimilar([0, 1], [0, 1]))
print(areSimilar([0, 1], [2, 3]))
这将输出:
True
True
False
答案 2 :(得分:1)
您可以尝试以下操作:-
def areSimilar(a,b):
if len(a)<2 or len(b)<2:
return 'Wrong input'
if len(a) != len(b):
return False
if len(a) == len(b) == 2:
if (a[0] != b[0] and a[0] != b[1]) or (a[1] != b[0] or a[0] != b[1]):
return False
else: return True
var = 0
for i, j in zip(a,b):
if i!=j:
var += 1
if var > 2:
return False
if var != 2:
return False
return True
>>> a= [832, 998, 148, 570, 533, 561, 894, 147, 455, 279]
>>> b= [832, 998, 148, 570, 533, 561, 455, 147, 894, 279]
>>> areSimilar(a,b)
True
答案 3 :(得分:0)
基于@Prune答案的解决方案。它在4秒内执行,但也许您可以写得更好
def areSimilar (a,b):
counter=0
ind1=[]
ind2=[]
if len(a) == len(b):
for i in range(len(a)):
if a[i] != b[i]:
counter+=1
ind1.append(a[i])
ind2.append(b[i])
if counter == 2:
if ind1[0] == ind2[1] and ind1[1] == ind2[0]:
flag= True
else:
flag = False
else:
flag= False
if counter == 0:
flag= True
elif counter ==1 or counter > 2:
flag=False
return flag
答案 4 :(得分:-1)
它不是很紧凑,但是可以工作。
由于您正在测试精确位置是否为相同值(最多交换1次),因此可以使用相同的循环。
如果不满足某些条件(例如数组的长度)并且数组甚至包含相同的元素(不包括位置),我已经使下面的代码立即返回。然后,for循环测试位置,并尝试1个2个元素的交换。交换元素的位置必须大于先前测试的位置,因为我们不想重新测试元素。
def areSimilar(a, b):
flag = False
swap = False
if len(a) is not len(b):
return False
arrlen = len(a)
if set(a) == set(b):
pos1 = None
pos2 = None
for i in range(arrlen):
if a[i] == b[i]:
flag = True
else:
if pos1 is None:
if swap is False:
swap = True
pos1 = i
pos2 = b.index(a[i])
if pos2 > i:
flag = True
else:
return False
else:
if b[pos1] == a[i]:
flag = True
else:
return False
return flag
a = [832, 998, 148, 570, 533, 561, 894, 147, 455, 279]
b = [832, 998, 148, 570, 533, 561, 455, 147, 894, 279]
print(areSimilar(a,b))