单调队列&单调栈

单调队列

原理

普通队列就如果食堂打饭一样,先进先出,而单调队列的元素具有单调性(递增或者递减),在保持元素进出的相对顺序不变,维持了大小顺序。如排队过程中突然有个人高马大的小伙过来,来到队尾看到别人比他矮好欺负,把别人赶走,一旦打不过别人就乖乖排队。

图片名称

如上图,原始数据为 1,3,6,2,5,1,7,添加 6 后单调递增队列为 1,3,6, 现在添加 2 到队尾,单调队列弹出比 2 大的数,并加入 2 后变为 1,2

应用

可用于求解滑动窗口最值问题,如下面 leetcode 问题。

图片名称

思路:维持一个单调递减队列,记录各个元素的位置(下标),队首元素就是窗口最大值的下标,窗口在滑动过程中,不属于窗口的元素从队首弹出,而队尾在满足单调队列的性质下加入当前元素。

class Solution {
public:
	vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        if(nums.empty()) return {};
		deque<int>dq;
		for (int i = 0; i < k; ++i) {
			while (!dq.empty() && nums[i] > nums[dq.back()]) {
				dq.pop_back();
			}
			dq.push_back(i);
		}
		int n = nums.size();
		vector<int>res(n - k + 1);
		res[0] = nums[dq.front()];
		for (int i = k; i < n; ++i) {
			while (!dq.empty() && nums[i] > nums[dq.back()]) {
				dq.pop_back();
			}
			dq.push_back(i);
			while (dq.front() <= i - k) {
				dq.pop_front();
			}
		
			res[i - k + 1] = nums[dq.front()];
		}
		return res;
	}
};

单调栈

和单调队列类似,不同的是满足元素后进先出。主要处理一下几种问题:

  • 比当前元素更大的下一个元素

  • 比当前元素更大的前一个元素

  • 比当前元素更小的下一个元素

  • 比当前元素更小的前一个元素

可通过单调递增/递减栈,外加遍历顺序(顺序,逆序)实现以上功能。

问题

图片名称
图片名称

因为问的是后面哪天比今天温度高,所以从后往前遍历。

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        if(temperatures.empty()) return {};
        int n = temperatures.size();
        stack<int>stk;
        vector<int>res(n);
        for(int i = n-1; i >=0; --i){
            while(!stk.empty() && temperatures[i] >= temperatures[stk.top()]){
                stk.pop();
            }
            if(stk.empty()) res[i] = 0;
            else{
                res[i] = stk.top() - i;
            }
            stk.push(i);
        }
        return res;
    }
};

总结

无论单调栈还是单调队列,比较队尾元素和新的待加入元素,是否能取到等号需要根据具体问题来确定,想像取到等号对问题的解答是否有影响。

posted @   wenchu1995  Views(32)  Comments(0Edit  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示