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


    虾皮一面问了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 替代也是可以的。

    心之所愿,永不相忘
  • 相关阅读:
    使用自制事务进行异常信息的记录:Autonomous transactionslog
    backup methodsexp and imp
    一个 SQL 同时验证帐号是否存在、密码是否正确
    使用存储过程进行分页:page by Procedure
    推荐一款类似于editplus的文本编辑工具:note++
    myeclipse8.5反编译插件的安装使用jdgui插件
    [转]JavaMail的使用之邮件发送 详解
    Thinking in java中内部类的例子。
    [转]tomcat6.0下的log4j日志文件配置过程
    127.X.X.X開頭的網路都是特殊用途的嗎!?
  • 原文地址:https://www.cnblogs.com/zgll/p/15465997.html
Copyright © 2020-2023  润新知