剑指虾皮-滑动窗口最大值

虾皮一面问了redis、MySQL、Http,前面答得都很好,面试官评价也挺好的,然后面试官说做完这个算法题,如果能做出来,面试就过了。

面试题:滑动窗口最大值JZ59

我的思路:

  • 通过双指针实现窗口(大小为k)在数组(大小为n)上的滑动,并用一个索引记录当前窗口最大值的位置,如果最大值被划出窗口了,就重新计算新窗口的最大值。
  • 这样的时间复杂度是O(nk)
 1 class Solution {
 2 public:
 3     // 记录滑动窗口的最大值=》减少向量比较次数   
 4     vector<int> maxInWindows(const vector<int>& num, unsigned int size) {
 5         // 双指针
 6         int vlen=num.size();
 7         vector<int> res;
 8         if(vlen<size || size==0){
 9             return res;
10         }
11         // 记录最大值索引值更好点,key可以直接定位val,但val不能定位key
12         int lp=0,rp=size-1;
13         int maxIdx=maxValue(num,lp,rp);    // 处理边界
14         lp++;rp++;
15         res.push_back(num[maxIdx]);
16         while(rp<vlen){
17             if(num[rp]>num[maxIdx]){   // 先把rp元素拉入区间
18                 maxIdx=rp;
19             }
20             if(maxIdx<lp){   // 如果最大值的索引值已经在区间左侧了
21                  maxIdx=maxValue(num,lp,rp);
22             }
23             res.push_back(num[maxIdx]);
24             ++lp;++rp;
25         }
26         return res;
27     }
28     
29     // 返回一个窗口的最大值的索引值
30     int maxValue(vector<int> wick,int lp,int rp){
31         int maxIndex=lp;
32         for(int i=lp+1;i<=rp;++i){
33             maxIndex=wick[i]>wick[maxIndex]?i:maxIndex;
34         }
35         return maxIndex;
36     }
37 };

然后,我做出来了,面试官从最开始的高评价变成了整体还不错,然后就收到感谢信了!!!!

面试官最后说这题的思路应该是用优先队列,看了下牛客,记录下用双端队列的解题思路吧。

双端队列的核心思想:

  • 记录一个窗口起点为最大值,终点为当前值的递减序列,如果6 2 5 2 4 1 7,窗口大小为5,那么双端队列的第一个窗口存储值就是6 5 4;

当6被划出去后,5就是当前窗口最大值了。 因此,我们在将当前值插入队列时,需要从后到前删除比它小的值。

  • 为了判断6什么时候会被划走,不是直接存储val 6 而是存储 key 0. 当 i-deque.front+1>k时,就表示上个窗口的最大值被移走了。
 1 class Solution {
 2 public:
 3     vector<int> maxInWindows(const vector<int>& num, unsigned int size) {
 4         vector<int> res;
 5         deque<int> deq;
 6         int len=num.size();
 7         // 这个条件判断很重要,面试官也是针对这个问题说了我下
 8         if(num.empty() || size<=0 || size>len) return res;
 9         for(int i=0;i<len;++i){
10             while(!deq.empty() && num[deq.back()]<num[i]){deq.pop_back();}
11             while(!deq.empty() && i-deq.front()+1>size){deq.pop_front();}
12             // 将当前索引追加到双端队列尾巴
13             deq.push_back(i);
14             // 当窗口为size时,才写入结果
15             if(i+2>size){res.push_back(num[deq.front()]);}
16         }
17         return res;
18     }
19 };

这种方法时间复杂度是O(n),比如最坏的情况,整个数组是顺序的,执行时间好像也只是T(2n),第二个while用 if 替代也是可以的。

心之所愿,永不相忘
原文地址:https://www.cnblogs.com/zgll/p/15465997.html