代码随想录算法训练营第41天|739. 每日温度、496.下一个更大元素 I、503.下一个更大元素II
LeetCode739
2025-03-16 17:57:12 星期日
题目描述:力扣739
文档讲解:代码随想录(programmercarl)739. 每日温度
视频讲解:《代码随想录》算法视频公开课:单调栈,你该了解的,这里都讲了!LeetCode:739.每日温度
代码随想录视频内容简记
什么样的题目是是用单调栈呢?就是一旦出现需要我们去找到当前元素左边或者右边第一个比他大或者小的元素
单调栈的作用就是存放之前遍历过的元素,然后和当前元素做一个对比。
单调栈存放的是什么呢?不是具体每一个元素,而是每一个元素的下标,这样才能和每一个元素一一对应上,因为单纯看元素的话,他每一个元素是会有重复的情况。
梳理
-
首先初始化一个栈,和一个result初始化为0
-
存放温度数组中第一个元素,之后开始for循环遍历
-
如果当前元素比栈顶元素小,那么入栈
-
如果当前元素和栈顶元素相等,那么入栈
-
如果当前元素比栈顶元素大,那么这里就是要收获结果的地方了。使用一个while循环,表示重复比较(有点像消消乐,之前比栈顶元素小或者等于的都先存起来,一旦有一个比栈顶元素大的,那么之前的也都能消掉,每一个计算距离),首先是这里对应的数组下标是
result[st.top()]
,之后他的值就是当前元素和栈顶元素的差i - st.top()
,表示二者之间的距离,以此表示“隔了多少天”。之后弹出栈顶元素的同时,将当前元素入栈,继续保持单调递增或者单调递减即可。
-
3. 返回result即可
LeetCode测试
注意,这里在弹出栈顶元素的时候,不要忘了把当前元素也入栈
点击查看代码
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> st;
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();
st.pop();
}
st.push(i);
}
}
return result;
}
};
LeetCode496
题目描述:力扣496
文档讲解:代码随想录(programmercarl)496.下一个更大元素 I
视频讲解:《代码随想录》算法视频公开课:单调栈,套上一个壳子就有点绕了| LeetCode:496.下一个更大元素
代码随想录视频内容简记
这道题特殊的一个地方就是需要做一个映射,除此以外,其他的部分和上面的每日温度都差不多
另外,最后的result数组是和nums1的长度保持一致的,所以大体流程就是在nums2中做一个单调栈进行遍历,每当有比当前元素更大的元素出现,那么就去nums1中看看该元素是否存在,若存在,那么找到该元素在nums1中映射的下标,进行赋值
还有就是本题的数组中没有重复元素
给你两个没有重复元素的数组 nums1 和 nums2
梳理
-
首先初始化一个栈,一个result数组初始化为-1
-
做一个映射,这道题是需要将nums1中的每一个元素映射到一个map,具体就是
for(int i = 0; i < nums1.size(); i++) map[nums1[i]] = i;
这一步就是将nums1[i]作为k,而i作为对应的v,将每一个元素直接映射到他的下标。 -
栈中添加一个元素,st.push(0),之后遍历时分三种情况
-
如果当前元素比栈顶元素小,那么入栈
-
如果当前元素和栈顶元素相等,那么入栈
-
如果当前元素比栈顶元素大,那么还是用while循环,之后首先需要判断当前元素是否在nums1中出现过,
if (map.count(st.top()) > 0) result = nums[i]
,之后进行pop()和入栈操作即可
-
-
返回result数组
LeetCode测试
这里有个小细节,就是这里的st.pop()是不能放在if判断里的,因为即使nums1中没有出现过对应的index元素,那么也需要弹出当前元素
while (!st.empty() && nums2[i] > nums2[st.top()]) {
if (map.count(nums2[st.top()]) > 0) {
int index = map[nums2[st.top()]];
result[index] = nums2[i];
}
st.pop();
}
点击查看代码
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int, int> map;
vector<int> result(nums1.size(), -1);
stack<int> st;
st.push(0);
for (int i = 0; i < nums1.size(); i++) map[nums1[i]] = i;
for (int i = 1; i < nums2.size(); i++) {
if (nums2[i] < nums2[st.top()]) st.push(i);
else if (nums2[i] == nums2[st.top()]) st.push(i);
else {
while (!st.empty() && nums2[i] > nums2[st.top()]) {
if (map.count(nums2[st.top()]) > 0) {
int index = map[nums2[st.top()]];
result[index] = nums2[i];
}
st.pop();
}
st.push(i);
}
}
return result;
}
};
LeetCode503
题目描述:力扣503
文档讲解:代码随想录(programmercarl)503.下一个更大元素II
视频讲解:《代码随想录》算法视频公开课:单调栈,成环了可怎么办?LeetCode:503.下一个更大元素II
代码随想录视频内容简记
本题是一个循环的单调栈,k哥在讲到的这道题目的时候重点强调了以后在处理这种环形问题的时候,都可以通过取模的方式
梳理
-
初始化一个栈st,一个result数组将其初始化为-1
-
压入第一个元素0,开始进行遍历。
for(i = 1; i < nums.size() * 2; i++)
,这里仍然需要遍历两倍数组,以确定最后一个数比他大或小的第一个元素位置。-
如果当前元素小于栈顶元素,入栈
-
如果当前元素等于栈顶元素,入栈
-
如果当前元素大于栈顶元素,用while循环,
while(!st.empty() && nums[i % nums.size()] < nums[st.top()])
,这里的每一个i都需要进行取模。之后result[i % nums.size()] = nums[i % nums.size()]
,这里不用担心会覆盖的问题,因为三种(单调递增,有增有减和单调递减都试过了,前两种的result结果都是一眼的,单调减的话整个第二部分nums会卡在st中,无法进行弹出和重写)情况都验证了。之后直接进行result赋值和pop()弹出即可,最后再入栈
-
-
返回result数组
LeetCode测试
点击查看代码
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
vector<int> result(nums.size(), -1);
stack<int> st;
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 if (nums[i % nums.size()] == nums[st.top()]) st.push(i % nums.size());
else {
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;
}
};