寻找最小范围的子数组

时间:2020-01-15 06:23:32

标签: python arrays algorithm range

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

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

答案将是[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)

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

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

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