我需要使用每个列表中至少一个元素从一组整数列表中找到最小范围。
list1=[228, 240, 254, 301, 391]
list2=[212, 345, 395]
list3=[15, 84, 93, 103, 216, 398, 407, 488]
在此示例中,最小范围为[391:398],因为这涵盖了三个列表中的值391,395和398.
每个列表至少有一个值,可能还有更多列表
找到范围的最快计算方法是什么?
答案 0 :(得分:5)
由于您的输入列表已排序,因此您可以使用合并排序,只需在合并的下一个值来自与上一个列表不同的列表时测试范围。跟踪您在每个列表上看到的最后一个值,并计算最低值和当前值之间的范围。这是O(N)
线性时间方法,其中N
是所有输入列表的元素总数。
以下实现了这种方法:
def smallest_range(*lists):
iterables = [iter(it) for it in lists]
iterable_map = {}
for key, it in enumerate(iterables):
try:
iterable_map[key] = [next(it), key, it]
except StopIteration:
# empty list, won't be able to find a range
return None
lastvalues, lastkey = {}, None
candidate, candidatediff = None, float('inf')
while iterable_map:
# get the next value in the merge sort
value, key, it = min(iterable_map.values())
lastvalues[key] = value
if len(lastvalues) == len(lists) and lastkey != key:
minv = min(lastvalues.values())
difference = value - minv
if candidatediff > difference:
candidate, candidatediff = (minv, value), difference
lastkey = key
try:
iterable_map[key][0] = next(it)
except StopIteration:
# this iterable is empty, remove it from consideration
del iterable_map[key]
return candidate
演示:
>>> list1 = [228, 240, 254, 301, 391]
>>> list2 = [212, 345, 395]
>>> list3 = [15, 84, 93, 103, 216, 398, 407, 488]
>>> smallest_range(list1, list2, list3)
(391, 398)
答案 1 :(得分:0)
当列表变得很大/很多时,此解决方案会显着减慢,但它并不假设输入列表是预先排序的:
end
<强> USAGE:强>
from itertools import product
def smallest_range(*arrays):
result = min((sorted(numbers) for numbers in product(*arrays)), key=lambda n: abs(n[0] - n[-1]))
return (result[0], result[-1])
list1 = [228, 240, 254, 301, 391]
list2 = [212, 345, 395]
list3 = [15, 84, 93, 103, 216, 398, 407, 488]
print(smallest_range(list1, list2, list3))
<强> PRINTS:强>
(391,398)