代码随想录算法训练营第58天 | 单调栈 ●739 每日温度 ●496下一个更大元素I

#单调栈知识:

单调栈就是保持栈内元素有序。和栈与队列(239. 滑动窗口最大值 自己写一个class来实现单调队列)一样,需要我们自己维持顺序,没有现成的容器可以用。

通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈。时间复杂度为O(n)。

单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优点是整个数组只需要遍历一次。


#739 每日温度 

用双指针半天写不出。gpt说这种题不能用双指针,得用单调栈。然后用单调栈自己写的:

stack里存的index,遇到更大的就记录,pop原来的,push新的。但是注意,会有不断遇到pop完之后新的top还是比新来的T[i]小,这时候要不断pop,全部pop完之后再 push一次。而不是push多次

vector<int> dailyTemperatures(vector<int>& T) {
       vector<int> res(T.size(),0);
       stack<int> mys;//store the index
       mys.push(0);
       for(int i=1;i<T.size();i++){
           if(T[i]<=T[mys.top()]) mys.push(i);
           else{
                while(!mys.empty() && T[i]>T[mys.top()]){
                    res[mys.top()]=i-mys.top();
                    mys.pop();
                }
                mys.push(i);
            }
       }
       return res;
    }

# 496下一个更大元素I

居然是easy,我不觉得是easy,感觉难度>=#739 每日温度 。太好了,随想录也 “ 看上去和739几乎一样,但是这么绕了一下,其实还上升了一点难度。需要对单调栈使用的更熟练一些,才能顺利的把本题写出来。”

自己写的时候只能想到先像#739那样,把一个弄一个一一对应的vector res把下一个最大的答案存进去,然后再从nums1去nums2里一一对应着找。我自己做的时候最困惑我的一点是:nums1和nums2顺序不同,nums1就很难用

下面是我的AC代码,基于#739的,然后加了一段 O n^2,感觉很慢

vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        vector<int> res(nums2.size(),-1);
        vector<int> res1(nums1.size(),-1);
        stack<int> mys;//store the index
        mys.push(0);
        for(int i=1;i<nums2.size();i++){
            if(nums2[i]<=nums2[mys.top()]) mys.push(i);
            else{
                    while(!mys.empty() && nums2[i]>nums2[mys.top()]){
                        res[mys.top()]=nums2[i];
                        mys.pop();
                    }
                    mys.push(i);
                }
        }
        for(int i=0;i<nums1.size();i++){
            for(int j=0;j<nums2.size();j++){
                if(nums1[i]==nums2[j]) res1[i]=res[j];
            }
        }
        return res1; 
    }

随想录思路:

对于nums1和nums2找对应: “遍历nums2过程中,要判断nums2[i]是否在nums1(小)中出现过,因为最后是要根据nums1元素的下标来更新result数组。注意题目中说是两个没有重复元素 的数组 nums1 和 nums2。没有重复元素,就可以用map来做映射了。根据数值快速找到下标,还可以判断nums2[i]是否在nums1中出现过。

C++中,当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的。”

改成用unordered map之后快太多了。然后记得if(umap.count(nums2[mys.top()])>0)这个不要忘了,不然不存在的value从umap里获取的idx是0,会出错

vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        vector<int> res(nums1.size(),-1);
        unordered_map<int,int> umap;
        for(int i=0;i<nums1.size();i++){
            umap[nums1[i]]=i;//key:val, value:idx
        }
    
        stack<int> mys;//store the index
        mys.push(0);
        for(int i=1;i<nums2.size();i++){
            if(nums2[i]<=nums2[mys.top()]) mys.push(i);
            else{
                    while(!mys.empty() && nums2[i]>nums2[mys.top()]){
                        if(umap.count(nums2[mys.top()])>0){
                            int idx_nums1=umap[nums2[mys.top()]];
                            res[idx_nums1]=nums2[i];
                        }
                        mys.pop();
                    }
                    mys.push(i);
                }
        }
        return res; 
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值