简体   繁体   中英

Finding the subarray with the minimum range

Given an array of N positive integers, ranging from index 0 to N - 1, how can I find a contiguous subarray of length K with the minimum range possible. In other words, max(subarray) - min(subarray) is minimised. If there are multiple answers, any is fine.

For example, find the subarray of length 2 with the smallest range from [4, 1, 2, 6]

The answer would be [1, 2] as 2 - 1 = 1 gives the smallest range of all possible contiguous subarrays.

Other subarrays are [4, 1] (range 3), [2, 6] (range 4)

I'm using python and so far I've tried a linear search with min() max() functions and it just doesn't seem efficient to do so. I've thought of using a minheap but I'm not sure how you would implement this and I'm not even sure if it would work. Any help would be much appreciated.

edit: code added

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

You could use numpy to improve execution time.

Example:

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

Small test ( f2 is your function here).

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

There is linear-time algorithm O(N) for getting min or max in moving window of specified size (while your implementation has O(N*K) complexity)

Using deque from collections module you can implement two parallel deques keeping minumum and maximum for current window position and retrieve the best difference after the only walk through the list.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM