代码算法训练营day13 | 239. 滑动窗口最大值、347.前 K 个高频元素

发布于:2024-04-09 ⋅ 阅读:(137) ⋅ 点赞:(0)

239. 滑动窗口最大值

题目链接
状态:暴力ok
文档:programmercarl.com

1、(暴力算法)思路:

一共有两层循环,外层循环(N)迭代变量,内层循环(K)每一个窗口,并计算这个窗口的最大值。时间复杂度O(N*K)。

代码:

class Solution {
public:
//暴力
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {  
        //短路条件
        int size = nums.size();
        //存放结果的数组
        vector<int> result;
        if(size == 0) return result;

        for(int i=0;i<=size-k;i++)
        {
            //最大值
            int max = nums[i];
            for(int j=i;j<=i+k-1;j++)
            {
                //计算每个窗口内的最大值
                if(nums[j] > max) max = nums[j];
            }
            result.push_back(max);
        }
        return result;
    }
};

2、(单调队列)思路:

239思路图
可以看到,每移动一次窗口,原理上都是把左边的元素pop出去,右边新加一个元素进来。
但是有时候并不需要去pop那个被窗口抛弃的元素,因为在某些元素push进来之前,我们会先对队列进行一个判断大小的操作:

  • 如果要push进来的元素比队列入口处的元素大,那么就要把这些元素一 一pop掉,(因此之后可能就不用去pop那个被窗口抛弃的元素,因为已经被pop掉了)这样就保证了队列是一个单调递减的队列。
  • 之后若要pop出口处的元素,那么下一个元素一定是下一个窗口的最大值。
  • 并且,若pop的元素==队列出口的元素,那么说明pop的元素是这个窗口的最大值。

代码:

class Solution {
private:
    class MyQueue{
    public:
        //定义一个队列que,实现单调队列
        deque<int> que;
        // 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
        // 如果不相等的话说明此时要pop的数比出口数小,在出口数push前该数就已经被pop了。
        // 同时pop之前判断队列当前是否为空。
        void pop(int value){
            if(!que.empty() && value == que.front())
                que.pop_front();
        }

        // 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
        // 这样就保持了队列里的数值是单调从大到小的了。
        void push(int value){
            while(!que.empty() && value > que.back())
                que.pop_back(); // 把小的数都pop
            //小的数pop完再push新的大的数
            que.push_back(value);
        }
        
        // 返回窗口最大值
        int getWindowMax(){
            return que.front();
        }
    };
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        MyQueue que;
        vector<int> result;
        //先把前k个数放到que中
        for(int i=0;i<k;i++){
            que.push(nums[i]);  // 已经保证现在的队列是一个单调队列了
        }
        // 此时已经产生了一个窗口的最大值,记录下来
        result.push_back(que.getWindowMax()); 

        // 窗口移动时,左边的元素被移除,右边的元素会新加进来
        for(int j=k;j<nums.size();j++){
            // 左边的元素移除掉
            que.pop(nums[j-k]);
            // 右边的元素加进来
            que.push(nums[j]);
            // 形成了新的窗口,返回窗口的最大值
            result.push_back(que.getWindowMax()); 
        }
        return result;
    }
};

注意:
在push函数中,判断要加进来的value是否>队列入口处的值时,因为这个比较次数是不确定的,所以不能用if判断,而要用while判断才行。

347.前 K 个高频元素


网站公告

今日签到

点亮在社区的每一天
去签到