我正在研究一个练习问题,想使用递归找到两个列表之间的最小差异。例如,如果我有一个列表X,其值分别为[79、85、10]和一个列表,Y,其值分别为[78、80、87、12],则视差为4。
我尝试遍历两个列表,无法弄清楚如何找到差异的最小和,而不是仅返回对。
我希望此函数返回成对的滑雪者和滑雪者,但不能返回代表两个给定列表之间最小差异的总和。
答案 0 :(得分:1)
一种解决方案是使用NumPy在滑雪板列表中找到最接近的值(从Find nearest value in numpy array借用的NumPy函数)。然后遍历滑雪者并找到最接近的尺码。请记住,然后从列表中删除该大小。
import numpy as np
def find_nearest(array, value):
array = np.asarray(array)
idx = (np.abs(array-value)).argmin()
return array[idx]
def pair(x, y):
skier_skis = []
skis_left = list(y)
for skier in x:
skier_skis.append((skier, find_nearest(skis_left, skier)))
skis_left.remove(skier_skis[-1][1])
return skier_skis
skiers = [6, 11, 13]
skis = [5, 7, 9, 14]
pair(skiers, skis)
返回[(6,5),(11,9),(13,14)]。
如果您的目标只是返回最小视差,请遍历skier_skis列表并求和。
编辑:正如@Rivers Shall指出的那样,这可能并不总是返回最佳解决方案。
答案 1 :(得分:1)
这里有不同的方法,一种是蛮力的:
from itertools import combinations
def best_match_brute(skiers, skis):
all = [list(zip(skiers, c)) for c in combinations(skis, len(skiers))]
all_with_disparity = [(sum([abs(x-y) for x, y in result]), result) for result in all]
# assuming the best result is any one with the lowest disparity
return sorted(all_with_disparity )[0]
def main():
# making sure the collections are sorted to begin with
skiers = sorted([6, 11, 13])
skis = sorted([5, 7, 9, 14])
# all skiers should be able to get skis
assert len(skis) >= len(skiers)
print(best_match_brute(skiers, skis))
if __name__ == '__main__':
main()
如果您甚至坚持不使用诸如itertools.combinations
之类的标准库函数,那么我想您也可以自制,但是我不明白这一点:
def combinations(xs, n):
if n == 1:
for x in xs:
yield [x]
else:
while len(xs) >= n:
x = xs[0]
xs = xs[1:]
for c in combinations(xs, n-1):
yield [x] + c
答案 2 :(得分:0)
对不起,@ minterm发布的算法似乎是错误的。考虑skiers = [2, 12], skis = [0, 3]
。 @minterm程序给出[(2, 3), (12, 0)]
的最佳解是[(2,0), (12, 3)]
。 @minterm使用的算法是一种贪婪算法,始终需要严格的证明来证明其正确性。
我认为这是maximum-weight matching problem。我们可以将skiers
和skis
中的元素视为顶点,并且在每个元素skiers[i]
和skis[j]
之间放置一条权重为abs(skiers[i], skis[j])
的边。因此,示例类似于下图: