使用双端队列解决滑动窗口问题

时间:2020-06-28 20:27:17

标签: arrays algorithm deque sliding-window prefix-sum

我正在研究问题Shortest Subarray with Sum at Least K,其中最佳解决方案使用双端队列。

由于数组可以同时具有正值和负值,因此无法使用双指针技术。我了解为什么2指针技术无法正常工作。

我对使用双端队列的最佳解决方案的理解如下:

  • 在此解决方案中,最短子数组的所有可能的起始值都保存在双端队列中。
  • 双端队列存储数组的前缀和值,以便我们可以在恒定时间内计算起始元素和当前元素之间的和。
  • 双端队列单调递增,因为如果我们有prefix = [a, b, c]prefix[b] < prefix[a](c-b) > (c-a),并且由于[b,c]小于[a,b,c],双端队列单调递增。

总和至少为k的最短子数组的代码如下:

public int shortestSubarray(int[] a, int k) {
    Deque<Integer> deque = new LinkedList<>();
    int res = a.length+1;
    
    int[] prefix = new int[a.length+1];
    for(int i = 1; i<prefix.length; i++)
        prefix[i] = prefix[i-1] + a[i-1];
    
    for(int i = 0; i<prefix.length; i++) {
        // increment start pointer when condition is violated 
        // this first while loop is same as what happens in the 2 pointer approach
        while(!deque.isEmpty() && prefix[i] - prefix[deque.peekLast()] >= k) {
            res = Math.min(res, i - deque.peekLast());
            deque.removeLast();
        }
        
        // this is what changes the solution from 2 pointer
        // we filter out candidates that cannot be the start for min subarray
        while(!deque.isEmpty() && prefix[i] <= prefix[deque.peekFirst()]) {
            deque.removeFirst();
        }
        
        deque.addFirst(i);
    }
    
    return res == a.length+1? -1 : res;
}

我想我理解为什么这种特殊的解决方案有效,但是我仍然困惑何时可以使用双端队列来优化滑动窗口问题。


我的问题

我开始考虑如果问题是找到总和为最小K的最长子阵列而不是最短子阵列,

  1. 如果我改变问题以至于需要找到最小和为S的最长子数组,我是否仍然可以类似的方式使用双端队列?
  2. 如果可以使用双端队列,解决方案将是什么样?您如何计算所有不同的起始位置?我们可以尝试使其成为单调减少的队列,但我认为这不能解决问题。
  3. 如果不能使用双端队列在O(n)时间内解决问题,那么有人可以给我一个令人信服的论点,为什么不能在O(n)时间内用双端队列解决问题?

谢谢。

0 个答案:

没有答案