Day50 739每日温度 496下一个更大元素I 503下一个更大元素II

739 每日温度

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = 73, 74, 75, 71, 69, 72, 76, 73,你的输出应该是 1, 1, 4, 2, 1, 1, 0, 0

提示:气温 列表长度的范围是 1, 30000。每个气温的值的均为华氏度,都是在 30, 100 范围内的整数。

本题利用单调栈的方法:栈里存放的是之前遍历过的元素的下标,后面遍历的元素与栈顶比较,按照本题为例,如果大于栈头,就将result更新,同时继续比较下一个,直到小于等于那么这个元素入栈,继续比较剩下的元素。如果求一个元素右边第一个更大元素,单调栈就是递增的,如果求一个元素右边第一个更小元素,单调栈就是递减的。

首先先将第一个遍历元素加入单调栈


加入T1 = 74,因为T1 > T0(当前遍历的元素Ti大于栈顶元素Tst.top()的情况)。

我们要保持一个递增单调栈(从栈头到栈底),所以将T0弹出,T1加入,此时result数组可以记录了,result0 = 1,即T0右面第一个比T0大的元素是T1


加入T2,同理,T1弹出


加入T3,T3 < T2 (当前遍历的元素Ti小于栈顶元素Tst.top()的情况),加T3加入单调栈。


加入T4,T4 == T3 (当前遍历的元素Ti等于栈顶元素Tst.top()的情况),此时依然要加入栈,不用计算距离,因为我们要求的是右面第一个大于本元素的位置,而不是大于等于!


加入T5,T5 > T4 (当前遍历的元素Ti大于栈顶元素Tst.top()的情况),将T4弹出,同时计算距离,更新result


T4弹出之后, T5 > T3 (当前遍历的元素Ti大于栈顶元素Tst.top()的情况),将T3继续弹出,同时计算距离,更新result


直到发现T5小于Tst.top(),终止弹出,将T5加入单调栈


加入T6,同理,需要将栈里的T5,T2弹出


同理,继续弹出


此时栈里只剩下了T6


加入T7, T7 < T6 直接入栈,这就是最后的情况,result数组也更新完了。

cpp 复制代码
// 版本一
class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& T) {
        // 递增栈
        stack<int> st;
        vector<int> result(T.size(), 0);
        st.push(0);
        for (int i = 1; i < T.size(); i++) {
            if (T[i] < T[st.top()]) {                       // 情况一
                st.push(i);
            } else if (T[i] == T[st.top()]) {               // 情况二
                st.push(i);
            } else {
                while (!st.empty() && T[i] > T[st.top()]) { // 情况三
                    result[st.top()] = i - st.top();
                    st.pop();
                }
                st.push(i);
            }
        }
        return result;
    }
};

简化版本:

cpp 复制代码
// 版本二
class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& T) {
        stack<int> st; // 递增栈
        vector<int> result(T.size(), 0);
        for (int i = 0; i < T.size(); i++) {
            while (!st.empty() && T[i] > T[st.top()]) { // 注意栈不能为空
                result[st.top()] = i - st.top();
                st.pop();
            }
            st.push(i);

        }
        return result;
    }
};

496 下一个更大元素I

给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。

请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。

nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。

示例 1:

输入: nums1 = 4,1,2, nums2 = 1,3,4,2.

输出: -1,3,-1

解释:

对于 num1 中的数字 4 ,你无法在第二个数组中找到下一个更大的数字,因此输出 -1 。

对于 num1 中的数字 1 ,第二个数组中数字1右边的下一个较大数字是 3 。

对于 num1 中的数字 2 ,第二个数组中没有下一个更大的数字,因此输出 -1 。

示例 2:

输入: nums1 = 2,4, nums2 = 1,2,3,4.

输出: 3,-1

解释:

对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。

对于 num1 中的数字 4 ,第二个数组中没有下一个更大的数字,因此输出-1 。

本题继承了上一题的思路,也是一个单调栈问题,把nums2的元素放入到单调栈之中,依次进行判断如果小了继续塞,如果大了的话就找这个元素是否在nums1里面出现过,之前已经定义了一个关于映射nums1里面下标和值的哈希表,如果栈顶元素在nums1里面出现过,就将nums1对应位置的值设置成用来比较的那个大值即可:

cpp 复制代码
// 版本二
class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        stack<int> st;
        vector<int> result(nums1.size(), -1);
        if (nums1.size() == 0) return result;

        unordered_map<int, int> umap; // key:下标元素,value:下标
        for (int i = 0; i < nums1.size(); i++) {
            umap[nums1[i]] = i;
        }
        st.push(0);
        for (int i = 1; i < nums2.size(); i++) {
            while (!st.empty() && nums2[i] > nums2[st.top()]) {
                if (umap.count(nums2[st.top()]) > 0) { // 看map里是否存在这个元素
                    int index = umap[nums2[st.top()]]; // 根据map找到nums2[st.top()] 在 nums1中的下标
                    result[index] = nums2[i];
                }
                st.pop();
            }
            st.push(i);
        }
        return result;
    }
};

503.下一个更大元素II

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

本题相比于接雨水,新加了成环的规则,对于成环,我们有两种方法,一种是两倍长度拼接,这样空间复杂度翻倍了,还有一种就是取模法:

cpp 复制代码
// 版本一
class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        // 拼接一个新的nums
        vector<int> nums1(nums.begin(), nums.end());
        nums.insert(nums.end(), nums1.begin(), nums1.end());
        // 用新的nums大小来初始化result
        vector<int> result(nums.size(), -1);
        if (nums.size() == 0) return result;

        // 开始单调栈
        stack<int> st;
        st.push(0);
        for (int i = 1; i < nums.size(); i++) { 
            if (nums[i] < nums[st.top()]) st.push(i); 
            else if (nums[i] == nums[st.top()]) st.push(i);
            else { 
                while (!st.empty() && nums[i] > nums[st.top()]) {
                    result[st.top()] = nums[i];
                    st.pop();
                }
                st.push(i);
            }
        }
        // 最后再把结果集即result数组resize到原数组大小
        result.resize(nums.size() / 2);
        return result;
    }
};
cpp 复制代码
class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        vector<int> result(nums.size(), -1);
        if (nums.size() == 0) return result;
        stack<int> st;
        for (int i = 0; i < nums.size() * 2; i++) {
            // 模拟遍历两边nums,注意一下都是用i % nums.size()来操作
            while (!st.empty() && nums[i % nums.size()] > nums[st.top()]) {
                result[st.top()] = nums[i % nums.size()];
                st.pop();
            }
            st.push(i % nums.size());
        }
        return result;
    }
};
相关推荐
Qt程序员7 小时前
掌握 Linux 内核调度:从原理到实现(进程篇)
java·开发语言
code bean7 小时前
【LangChain】检索器完全指南:从向量检索到生产级 RAG 架构
java·开发语言·微服务
大白菜和MySQL7 小时前
java应用排查高线程
java·python
KobeSacre7 小时前
ReentrantLock源码
java
嵌入式协会20240727 小时前
(已解决)MinIO python 获取预签名出现forbidden、errornetwork等错误
java·开发语言·python
不才不才不不才7 小时前
Spring AI 实战:聊天、提示词、记忆三件套
java·人工智能·spring·ai
北域码匠7 小时前
SHA-1算法:安全哈希原理与应用解析
算法·c#·哈希算法
手写码匠8 小时前
手写 GraphRAG:从零实现图增强检索增强生成系统
人工智能·深度学习·算法·aigc
BomanGe18 小时前
NSK重载高刚性滚珠丝杠技术详解
经验分享·算法·规格说明书
一 乐9 小时前
家政服务管理系统|基于springboot + vue家政服务管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·家政服务管理系统