【问题标题】:python smallest range from multiple listspython 多个列表中的最小范围
【发布时间】:2016-12-14 16:36:23
【问题描述】:

我需要使用每个列表中的至少一个元素从一组整数列表中找到最小范围。

list1=[228, 240, 254, 301, 391]
list2=[212, 345, 395]
list3=[15, 84, 93, 103, 216, 398, 407, 488]

在本例中,最小范围为 [391:398],因为这涵盖了三个列表中的值 391、395 和 398。

每个列表至少有一个值,并且可以有更多列表

找到范围的最快计算方法是什么?

【问题讨论】:

  • 为什么不是 [391:395]?
  • 我认为 (395, 398) 是最小的。
  • 使用每个列表中至少一个元素的最小范围是 [391:398]。使用 391、395 和 398

标签: python algorithm list range


【解决方案1】:

随着列表变大/很多,此解决方案会显着减慢速度,但它不假设输入列表是预先排序的:

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))

用法:

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))

打印:

(391, 398)

【讨论】:

  • 既然可以使用min(),为什么还要使用sorted()?而abs(numbers[0] - numbers[-1]) 实际上应该只是keymin() 函数。尽管如此,这仍然是非常低效的,因为产品的数量随着列表中元素的数量(以及列表的数量)呈指数增长。
  • 如果数字没有排序,在将它们传递给我的方法之前很容易(而且便宜)对它们进行排序,给出O(NlogN) 解决方案。
  • @MartijnPieters,我不知道 min() 具有关键功能。谢谢你的提醒,我已经相应地缩短了我的代码。我相信我在第一句话中就承认了它的低效性质。我想证明基本问题并不过分复杂——即使有新添加的约束!
【解决方案2】:

由于您的输入列表已排序,因此您可以使用合并排序,并且只要下一个要合并的值来自与上一个不同的列表,您只需测试一个范围。跟踪您在每个列表中看到的最后一个值,并计算最低值和当前值之间的范围。这是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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-31
    • 1970-01-01
    • 2021-06-17
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    • 2020-01-18
    • 1970-01-01
    相关资源
    最近更新 更多