【问题标题】:Finding the subarray with the minimum range查找具有最小范围的子数组
【发布时间】:2020-05-01 21:42:19
【问题描述】:

给定一个由 N 个正整数组成的数组,范围从索引 0 到 N - 1,我如何才能找到一个长度为 K 且具有最小范围的连续子数组。换句话说, max(subarray) - min(subarray) 被最小化。如果有多个答案,任何一个都可以。

例如,从[4, 1, 2, 6]中找到最小范围为2的子数组

答案是 [1, 2],因为 2 - 1 = 1 给出了所有可能的连续子数组的最小范围。

其他子数组是[4, 1](范围3),[2, 6](范围4)

我正在使用 python,到目前为止,我已经尝试使用 min() max() 函数进行线性搜索,但这样做似乎效率不高。我曾考虑过使用 minheap,但我不确定你将如何实现它,我什至不确定它是否会起作用。任何帮助将不胜感激。

编辑:添加代码

# N = length of array_of_heights, K = subarray length
N, K = map(int, input().split(' '))
array_of_heights = [int(i) for i in input().split(' ')]



min_min = 100000000000000000000

# iterates through all subarrays in the array_of_heights of length K
for i in range(N + 1 - K):
    subarray = land[i : i + K]
    min_min = min(max(subarray)-min(subarray), min_min)

print(min_min)

【问题讨论】:

  • 你为此做了什么?你能分享你的代码吗?
  • 代码已添加,谢谢。
  • 我认为你必须保持一个大小为k 的窗口,同时像滑动窗口一样沿着数组迭代。
  • 你需要一个 minheap 和一个 maxheap。并且代码将实现一个滑动窗口。当一个元素进入窗口时,它应该被添加到两个堆中。当最大值离开窗口时,它应该从 maxheap 中移除。 maxheap 中已经在窗口之外的其他元素也应该被删除。最低限度也是如此。

标签: python arrays algorithm range


【解决方案1】:

您可以使用 numpy 来缩短执行时间。

例子:

def f1(l,k):
    subs = np.array([l[i:i+k] for i in range(len(l)-k+1)])
    return np.min(subs.max(axis=1) - subs.min(axis=1))

小测试(f2 是你的功能)。

>>> arr = np.random.randint(100,size=10000)
>>> timeit.timeit("f1(arr,4)",setup="from __main__ import f1,f2,np,arr",number=1)
0.01172515214420855
>>> timeit.timeit("f2(arr,4)",setup="from __main__ import f1,f2,np,arr",number=1)
14.226237731054425

【讨论】:

  • 出于兴趣,是什么导致了这里标记的时差? Numpy 让它运行得更快...
  • @BrandonRu 有一个答案在这里给出了一个想法stackoverflow.com/a/8385658/171450 但基本上你正在使用更高效的结构,在 C 中使用为批量数组操作构建的算法。
【解决方案2】:

linear-time algorithmO(N)用于在指定大小的移动窗口中获取最小值或最大值(而您的实现具有O(N*K) 复杂度)

使用来自collections 模块的deque,您可以实现两个并行双端队列,保持当前窗口位置的最小值和最大值,并在唯一遍历列表后检索最佳差异。

import collections

def mindiff(a, k):
    dqmin = collections.deque()
    dqmax = collections.deque()
    best = 100000000
    for i in range(len(a)):
        if len(dqmin) > 0 and dqmin[0] <= i - k:
            dqmin.popleft()
        while len(dqmin) > 0 and a[dqmin[-1]] > a[i]:
            dqmin.pop()
        dqmin.append(i)
        if len(dqmax) > 0 and dqmax[0] <= i - k:
            dqmax.popleft()
        while len(dqmax) > 0 and a[dqmax[-1]] < a[i]:
            dqmax.pop()
        dqmax.append(i)
        if i >= k - 1:
            best = min(best, a[dqmax[0]]-a[dqmin[0]])
    return best

print(mindiff([4, 1, 2, 6], 2))

【讨论】:

    猜你喜欢
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 2017-01-17
    • 2018-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多