找到给定大小的每个连续子阵列的最大值

时间:2016-10-06 00:07:11

标签: python algorithm data-structures queue

我正在尝试解决Python中的以下问题

  

给定一个数组和一个整数k,找到每个大小为k的连续子阵列的最大值。

想法是使用双端队列。这是我的代码:

def diff_sliding_window(arr, win):
#     max = -inf
    Q = []
    win_maxes = [] # max of each window
    for i in range(win):
        print(Q)
        while len(Q) > 0 and arr[i] >= arr[len(Q) - 1]:
            # get rid of the index of the smaller element
            Q.pop() # removes last element
        Q.append(i)
#     print('>>', Q)

    for i in range(win, len(arr)):
#         win_maxes.append(arr[Q[0]])
        print(arr[Q[0]])
        while len(Q) > 0 and Q[0] <= i - win:
            Q.pop()
        while len(Q) > 0 and arr[i] >= arr[len(Q)-1]:
            Q.pop(0)
        Q.append(i)
#     win_maxes.append(arr[Q[0]])

    print(arr[Q[0]])

但我无法弄清楚测试用例的原因:

t1 = [1, 3, -1, -3, 5, 3, 6, 7]
t2 = [12, 1, 78, 90, 57, 89, 56]

我没有得到正确的结果。

更新

我做了Matt Timmermans建议的改动,但我仍然没有得到正确的输出。适用于t2win = 3

78
90
90
89 <--- should be 90
89

这是我更新的代码:

from collections import deque

def diff_sliding_window(arr, win):
#     max = -inf
    Q = deque()
    win_maxes = [] # max of each window
    for i in range(win):
#         print(Q)
        while len(Q) > 0 and arr[i] >= arr[Q[len(Q)-1]]:
            # get rid of the index of the smaller element
            Q.pop() # removes last element
        Q.append(i)
#     print('>>', Q)

    for i in range(win, len(arr)):
#         win_maxes.append(arr[Q[0]])
        print(arr[Q[0]])
        while len(Q) > 0 and Q[0] <= i - win:
            Q.pop()
        while len(Q) > 0 and arr[i] >= arr[Q[len(Q)-1]]:
            Q.popleft()
        Q.append(i)


    print(arr[Q[0]])

3 个答案:

答案 0 :(得分:2)

看起来你正在尝试为这个问题实现O(n)算法,这比此时的其他两个答案要好。

但是,您的实施不正确。如果你说arr[i] >= arr[len(Q)-1]应该arr[i] >= arr[Q[len(Q)-1]]arr[i] >= arr[Q[-1]]。您还在第二个循环中交换了poppop(0)个案例。修好后,它看起来是正确的。

此外,您的算法不是O(n),因为您使用Q.pop(0),这需要O(k)时间。因此,您的总运行时间为O(kn)。使用Q的双端队列将解决此问题。

这里已全部修复,并附有一些评论以显示其工作原理:

from collections import deque

def diff_sliding_window(arr, win):

    if win > len(arr):
        return []

    win_maxes = [] # max of each window

    #Q contains indexes of items in the window that are greater than
    #all items to the right of them.  This always includes the last item
    #in the window
    Q = deque()

    #fill Q for initial window
    for i in range(win):
        #remove anything that isn't greater than the new item
        while len(Q) > 0 and arr[i] >= arr[Q[-1]]:
            Q.pop()
        Q.append(i)

    win_maxes.append(arr[Q[0]])

    for i in range(win, len(arr)):
        #remove indexes (at most 1, really) left of window
        while len(Q) > 0 and Q[0] <= (i-win):
            Q.popleft()

        #remove anything that isn't greater than the new item
        while len(Q) > 0 and arr[i] >= arr[Q[-1]]:
            Q.pop()
        Q.append(i)
        win_maxes.append(arr[Q[0]])

    return win_maxes

试一试:https://ideone.com/kQ1qsQ

证明这是O(N):内部循环的每次迭代都会从Q中删除一个项目。因为总共只有len(arr)添加到Q,所以最多可以len(arr) < em>内部循环的总次迭代。

答案 1 :(得分:0)

这种方法怎么样(只需要对数据进行一次传递):

代码

def calc(xs, k):
    k_max = []
    result = []

    for ind, val in enumerate(xs):
        # update local maxes (all are active)
        for i in range(len(k_max)):
            if val > k_max[i] :
                k_max[i] = val
        # one new sub-array starts
        k_max.append(val)

        if ind >= (k-1):  # one sub-array ends
            result.append(k_max[0])
            k_max.pop(0)

    return result

t1 = [1, 3, -1, -3, 5, 3, 6, 7]
t2 = [12, 1, 78, 90, 57, 89, 56]
print(calc(t1, 3))
print(calc(t2, 2))

输出

[3, 3, 5, 5, 6, 7]
[12, 78, 90, 90, 89, 89]

答案 2 :(得分:0)

这是使用itertoolstee的简单解决方案:

def nwise(iterable, n):
    ''' Step through the iterable in groups of n '''
    ts = it.tee(iterable, n)
    for c, t in enumerate(ts):
        next(it.islice(t, c, c), None)
    return zip(*ts)

def max_slide(ns, l):
    return [max(a) for a in nwise(ns, l)]

>>> max_slide([1, 3, -1, -3, 5, 3, 6, 7], 3)
[3, 3, 5, 5, 6, 7]
>>> max_slide([12, 1, 78, 90, 57, 89, 56], 3)
[78, 90, 90, 90, 89]