Day58【单调栈】739.每日温度、496.下一个更大元素 I

739.每日温度

力扣题目链接/文章讲解

视频讲解

暴力解法很容易想到。外层 for 遍历填充 answer,内层 for 针对每一天去寻找下一个更高温度 

直接超时 

本题可以采用单调栈解决! 

什么是单调栈?

从名字上就听的出来,单调栈中存放的数据应该是有序的

维护单调栈的关键就是维护这个有序性,假设我们需要维护一个从栈顶到栈底单调递增的栈

在入栈元素时,如果栈为空入栈元素值小于栈顶元素值,则入栈

否则,如果直接入栈则会破坏栈的单调性,则需要先把比入栈元素小的栈顶元素全部出栈后,再入栈

本题怎么利用单调栈解决?本质上是利用一个栈来记录我们遍历过的元素

本题大致过程是单调栈中存放元素下标,按照元素值从栈顶到栈底递增存放,元素出栈时记录一次结果

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        
        stack<int> st;  
        // 递增栈,注意栈中存的是temperatures的下标,但“递增”形容的是temperatures的值
        // 递增栈指从栈顶到栈底元素递增

        vector<int> answer(temperatures.size(), 0);    // 存放结果,题目要求默认为0

        st.push(0);

        for (int i = 1; i < temperatures.size(); ++i) {
            if (temperatures[i] <= temperatures[st.top()])
                st.push(i); // 递增栈,当入栈元素小于等于栈顶元素,则入栈不会破坏单调性
            else {    // 否则需要不断将比入栈元素小的元素全部出栈
                while (!st.empty() && temperatures[i] > temperatures[st.top()])    // 注意栈非空
                {
                    answer[st.top()] = i - st.top();    // 出栈时记录一次结果
                    st.pop();
                }
                st.push(i);    // 然后再入栈
            }
        }

        return answer;        
    }
};

详细过程可以见视频讲解,感觉已经很清晰了 

496.下一个更大元素 I 

力扣题目链接/文章讲解 

视频讲解 

一维数组中,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素,此时我们又可以想到用单调栈 

需要用一个栈来记录遍历过的元素,本题我们要在 nums2 中找下一个更大元素,因此遍历 nums2,并用单调递增栈记录

在入栈元素时,如果栈为空入栈元素值小于栈顶元素值,则入栈

否则,如果直接入栈则会破坏栈的单调性,则需要先把比入栈元素小的栈顶元素全部出栈后,再入栈

本题大致过程是单调栈中存放元素,按照元素值从栈顶到栈底递增存放,元素出栈时记录结果

stack<int> st;    // 从栈顶到栈底元素单调递增的栈
st.push(nums2[0]);
for (int i = 1; i < nums2.size(); ++i) {    // 遍历nums2
    if (nums2[i] <= st.top())    // 入栈元素小于等于栈顶元素,直接入栈不会破坏单调性
        st.push(nums2[i]);
    else {
        while (!st.empty() && nums2[i] > st.top()) {    // 将比入栈元素小的元素全部出栈后
            
            // 元素出栈时做记录    
            
            st.pop();
        }
        st.push(nums2[i]);    // 再入栈
    }
}

此时我们看看怎么记录结果

根据题目要求,当出栈元素是 nums1 中的元素时,才记录在 nums1 中元素对应下标的位置

为了实现这种需求,我们先搭建一个 nums1 中元素到元素下标的映射

unordered_map<int, int> umap;   // k:nums1中元素 v:元素对应下标
for (int i = 0; i < nums1.size(); ++i)
    umap[nums1[i]] = i;

然后在记录结果的时候看看出栈元素是否为 nums1 中的元素即可

if (umap.count(st.top()) > 0)    // 刚才映射中有记录,说明出栈元素是nums1中的元素
{
    ans[umap[st.top()]] = nums2[i];
    // umap[st.top()]获取出栈元素在nums1中的下标位置,需要将结果记录在ans的该位置
    // nums2[i]就是出栈元素右侧的第一个比其大的元素  
}

整体代码如下 

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        
        vector<int> ans(nums1.size(), -1);

        unordered_map<int, int> umap;   // k:nums1中元素 v:元素对应下标
        for (int i = 0; i < nums1.size(); ++i)
            umap[nums1[i]] = i;

        stack<int> st;    // 从栈顶到栈底元素单调递增的栈
        st.push(nums2[0]);
        for (int i = 1; i < nums2.size(); ++i) {    // 遍历nums2
            if (nums2[i] <= st.top())    // 入栈元素小于等于栈顶元素,直接入栈不会破坏单调性
                st.push(nums2[i]);
            else {
                while (!st.empty() && nums2[i] > st.top()) {    // 先不断将比入栈元素小的元素全部出栈后
            
                    // 元素出栈时做记录   
                    if (umap.count(st.top()) > 0)    // 刚才映射中有记录,说明出栈元素是nums1中的元素
                    {
                        ans[umap[st.top()]] = nums2[i];
                        // umap[st.top()]获取出栈元素在nums1中下标位置,需要将结果记录在ans的该位置
                        // nums2[i]就是出栈元素右侧的第一个比其大的元素  
                    }
            
                    st.pop();
                }
                st.push(nums2[i]);    // 再入栈
            }
        }

        return ans;

    }
};

回顾总结 

单调栈的关键就是维护栈中元素的单调性 

关键就是入栈时候不能破坏栈中元素的单调性 

单调栈适合解决的问题:一维数组中,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素

单调栈解决问题的过程需要多看视频和动图解析,还是很容易理解的 

另外简单说一下确定递增递减栈的思路过程:(从栈顶到栈底递增还是递减)

找下一个更大,说明需要记录下一个更大,即遇到更大的入栈才需要出栈并记录,说明遇到更大的入栈会破坏单调性,因此是递增栈

找下一个更小,说明需要记录下一个更小,即遇到更小的入栈才需要出栈并记录,说明遇到更小的入栈会破坏单调性,因此是递减栈

 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林沐华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值