栈和队列:生成窗口最大值数组

题目:有一个整型数组arr和一个大小为w的窗口从数组的最左边滑到最右边,窗口每次向右滑一个位置。

例如,数组为[4,3,5,4,3,3,6,7],窗口大小为3时:

如果数组长度为n,窗口大小为w,则一共产生n-w+1个窗口的最大值。

请实现一个函数:

输入:整型数组arr,窗口大小为w。

输出:一个长度为n-w+1的数组res,res[i]表示每个窗口状态下的最大值。

以本题为例,结果应该返回{5,5,5,4,6,7}。

 

 

 

 

 

 

 

 

如果暴力求解时间复杂度为 O(N x w),这个结果显然不能让人满意,这里我们将介绍复杂度为 O(N)的解法。

本题的关键在于利于双端队列来实现窗口最大值的更新。首先生成双端队列 qmax,qmax中存放数组 arr 中的下标。

假设遍历 arr[i],qmax 的放入规则为:

1. 如果 qmax 为空,直接把下标 i 放入 qmax;

2. 如果qmax不为空,取出当前 qmax 队尾存放的下标,假设为 j,

a. 如果arr[j] > arr[i],直接把下标放入 qmax 的对尾

b. arr[j] <= arr[j],把 j 从 qmax 中弹出,继续 qmax 的放入规则

假设遍历到 arr[i],qmax 的弹出规则为:

如果 qmax 队头的下标等于 i-w,说明当前 qmax 队头的下标已经过期,弹出当前队头的下标即可。

根据上述放入和弹出规则,qmax便成了一个维护窗口为 w 的子数组的最大更新的结构。

下面举例说明给出的例子。

 

 1     public static int[] getMaxWindow(int[] arr, int w)
 2     {
 3         if(arr == null || w < 1 || arr.length < w)
 4             return null;
 5 
 6         Deque<Integer> qmax = new LinkedList<Integer>();
 7         int[] res = new int[arr.length - w + 1];
 8         int index = 0;
 9         for(int i = 0; i < arr.length; i++)
10         {
11             while(!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[i])
12             {
13                 qmax.pollLast();
14             }
15             qmax.addLast(i);
16             if(i - w == qmax.peekFirst())
17                 qmax.pollFirst();
18             if(i >= w - 1)
19                 res[index++] = arr[qmax.peekFirst()];
20         }
21 
22         return res;
23     }

 

 

参考:程序员代码面试指南 IT名企算法与数据结构题目最优解,左程云

 

posted on 2016-08-02 16:47  Traveling_Light_CC  阅读(214)  评论(0编辑  收藏  举报

导航