day 48 第十章 单调栈part01 739. 每日温度 49503.下一个更大元素II 6.下一个更大元素 I

任务日期:7.23

题目一链接:739. 每日温度 - 力扣(LeetCode)

思路:通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。
思路:
1.用一个栈来记录我们遍历过的元素,需要注意的是我们当前记录的是元素的下标而不是元素本身
2.注意以下讲解中,顺序的描述为 从栈头到栈底的顺序。只有单调栈递增(从栈口到栈底顺序),就是求右边第一个比自己大的,单调栈递减的话,就是求右边第一个比自己小的。
3.过程:首先定义一个单调栈,本题是递增栈,现将tem数组的第一个数的下标0压入栈中,然后便利后面的tem数组的下标,进行相应操作。
4.公式:result[st.top()] = i - st.top()通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。
思路:
1.用一个栈来记录我们遍历过的元素,需要注意的是我们当前记录的是元素的下标而不是元素本身
2.注意以下讲解中,顺序的描述为 从栈头到栈底的顺序。只有单调栈递增(从栈口到栈底顺序),就是求右边第一个比自己大的,单调栈递减的话,就是求右边第一个比自己小的。
3.过程:首先定义一个单调栈,本题是递增栈,现将tem数组的第一个数的下标0压入栈中,然后便利后面的tem数组的下标,进行相应操作。
4.公式:result[st.top()] = i - st.top()

代码:

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        stack<int> st; //递增栈;栈里的元素是tem数组里元素的下标
        vector<int> result(temperatures.size(),0); //记录栈顶元素的下标和右边第一个比他大的元素之间的下标差值
        st.push(0);
        for(int i = 1;i < temperatures.size();i ++) {
            if(temperatures[i] < temperatures[st.top()]) {
                st.push(i);
            }
            else if(temperatures[i] == temperatures[st.top()]) {
                st.push(i);
            }
            else {
                while(!st.empty() && temperatures[i] > temperatures[st.top()])
                {
                result[st.top()] = i - st.top(); //利用数组下标记录栈顶元素和当前元素的距离到result里
                st.pop(); //因为当前栈顶元素小于当前元素所以需要把当前栈顶元素弹出
                }
                st.push(i); //当栈顶元素大于当天元素时,需要把当前元素的下标压入栈中
            }
        }
        return result;
    }
};

难点:1.栈中压入的是数组下标,如果当前元素对应的值小于等于栈顶元素对应的值,那么就将当前元素压入栈中,否则就求得距离并弹出栈顶元素同时压入当前元素。
2.在当前元素对应的值大于栈顶元素对应的值得情况中,我们需要用while循环,因为当前元素可能比多个栈顶元素大,所以可能需要连续计算距离,弹出栈顶元素和压入当前元素的操作。




题目二链接:496. 下一个更大元素 I - 力扣(LeetCode)

思路:本题就是在上一题基础上加入了哈希表(是一个map数组)umap.find()的用法,用来快速判断某个之是否在数组中出现。
如果迷糊了就像我们的公式:result[st.top()] = i - st.top()
2.遍历nums2数组,如果当前栈顶元素对应的值在nums1中,则进行下一步判断,如果当前元素对应的值大于栈顶元素如果当前元素对应的值大于栈顶元素对应的值的话,就进行计算距离等操作,注意最后在while循环结束之后才进行st.push(i)的操作。

代码:

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        stack<int> st;//递增栈用于记录数组下标,后面直接
        vector<int> ans(nums1.size(),-1);
        if(nums1.size() == 0) return ans; //临界值:nums1没有元素
        
        unordered_map<int,int> umap; //定义一个哈希表,用来快速查找某个值:我们要判断nums2[i]是否在nums1中出现过,注意题目中说是两个没有重复元素的数组 nums1 和 nums2所以没有重复元素,我们就可以用map来做映射了(不会影响原来的数组)
        for(int i = 0;i < nums1.size();i ++) {
            umap[nums1[i]] = i; //将每个key(元素值)对应的value(元素下标)记录下来了
        }
        //开始对nums2数组进行遍历,其中加入了umap的用法用来判断nums2中的元素是否在nums1中出现
        st.push(0);//把第一个元素压入栈中
        for(int i = 1;i < nums2.size();i ++) {
            if(nums2[i] <= nums2[st.top()]) {
                st.push(i);
            }
            else {
                if(umap.find(nums2[st.top()]) != umap.end()) {
                    while(!st.empty() && nums2[i] > nums2[st.top()]) {
                        int index = umap[nums2[st.top()]]; //umap的使用需要借助一个变量;st.top()指nums2中最小的符合标准的元素下标;umap是nums1的一个哈希表(这里是一个map数组),通过数值取相应的下标
                        ans[index] = nums2[i];
                        st.pop(); //记录栈顶元素之后需要把它弹出,以便记录下一个
                    }
                }
                st.push(i); //当前符合的元素得压入栈中(压入的是下标) 
            }
        }
        return ans;
    }
};

难点:1.umap.find()和umap[nums2[i]]的区别
2.umap[num2[st.top()]]必须要用index赋值才能用;并且umap里是用的nums2的元素去nums1中寻找。
3.单调栈需要等到while循环结束之后才能把i压入栈中,并且不管栈顶元素在不在nums1中,i都得压入栈




题目三链接:503. 下一个更大元素 II - 力扣(LeetCode)

思路:本题在第一个每日温度的基础上多了一个循环数组,循环数组只需要让原来的i变成i % nums.size()即可

代码:

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        stack<int> st;
        vector<int> ans(nums.size(),-1);
        st.push(0);
        for(int i = 1;i < nums.size() * 2;i ++) {
            if(nums[i % nums.size()] <= nums[st.top()]) {
                st.push(i % nums.size());
            }
            else  {
                while(!st.empty() && nums[i % nums.size()] > nums[st.top()]) { //如果st为空或者当前元素小于栈顶元素,则跳出while循环:这里至少进行一次while
                    ans[st.top()] = nums[i % nums.size()];
                    st.pop();
                }
                st.push(i % nums.size()); //这里当i大于2时相当于重新覆盖原来的解果因此不会改变正确的结果
            }
        }
        return ans;
    }
};

难点:1.循环数组即对数组进行两次遍历,这样就能实现循环遍历了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值