【力扣分模块练习】单调栈

503. 下一个更大元素 II
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

示例 1:
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

题解:
用两个for暴力也能过,单调栈可以做一个优化使用。
如:[6,5,4,3,8] 对于6543来说,是递减的序列,他们的下一个较大值都是8,所以这里就存在优化的可能。

本题两个思路模式:
1.遇到循环数组,考虑遍历两轮。i < n *2 然后再取模 i = i %n。
2.对于「找最近一个比当前值大/小」的问题,都可以使用单调栈来解决。
单调栈就是在栈的基础上维护一个栈内元素单调。
在理解单调栈之前,我们先回想一下「朴素解法」是如何解决这个问题的。
对于每个数而言,我们需要遍历其右边的数,直到找到比自身大的数,这是一个 O(n^2)的做法。
之所以是 O(n^2),是因为每次找下一个最大值,我们是通过「主动」遍历来实现的。
而如果使用的是单调栈的话,可以做到 O(n)的复杂度,我们将当前还没得到答案的下标暂存于栈内,从而实现「被动」更新答案。
也就是说,栈内存放的永远是还没更新答案的下标
初始化的值要按照题目来变化。因为有些值(如最大值,或最后一个值(本题没有,下面739题就有)是没有办法出栈的,所以初始化要匹配最终结果)。

class Solution {
    
    
public:
	vector<int> nextGreaterElements(vector<int>& nums) {
    
    
		int n = nums.size();
		vector<int> res(n, -1);
		stack<int> st;

		for (int i = 0; i < n*2; i++)//处理循环数组,遍历两遍取模
		{
    
    
			//当前遍历的数比单调递减栈的栈顶大,即pop出来
			//这样表示当前的数是栈顶数的下一个较大值
			while (!st.empty() && nums[st.top()] < nums[i%n])
			{
    
    
				res[st.top()] = nums[i%n]; //写入“下一个较大值”
				st.pop(); //出栈
			}
			st.push(i%n); //栈内存放角标
		}
		return res;
	}
};

739. 每日温度
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

题解:
和上题几乎一模一样,是简化版。

class Solution {
    
    
public:
    vector<int> dailyTemperatures(vector<int>& T) {
    
    
        int n = T.size();
        vector<int> res(n,0);
        stack<int> st;

        for(int i = 0;i < n;i++)
        {
    
    
            //当前温度比单调栈内数值大,出栈
            while(!st.empty() && T[st.top()] < T[i])
            {
    
    
                res[st.top()] = i - st.top();
                st.pop();
            }
            st.push(i); //无论是否出栈,当前角标都要入栈
        }
        return res;
    }
};

猜你喜欢

转载自blog.csdn.net/abyss_miracle/article/details/114439009