题目 | 解法 |
---|---|
42. 接雨水(困难) | 暴力解法、优化、双指针、单调栈 |
739. 每日温度(中等) | 暴力解法 + 单调栈 |
496. 下一个更大元素 I(简单) | 暴力解法、单调栈 |
316. 去除重复字母(困难) | 栈 + 哨兵技巧 |
901. 股票价格跨度(中等) | |
402. 移掉K位数字 | |
581. 最短无序连续子数组 |
739. 每日温度
题目描述:
请根据每日气温列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用
0
0
0 来代替。例如,给定一个列表
t
e
m
p
e
r
a
t
u
r
e
s
=
[
73
,
74
,
75
,
71
,
69
,
72
,
76
,
73
]
temperatures = [73, 74, 75, 71, 69, 72, 76, 73]
temperatures=[73,74,75,71,69,72,76,73],你的输出应该是
[
1
,
1
,
4
,
2
,
1
,
1
,
0
,
0
]
[1, 1, 4, 2, 1, 1, 0, 0]
[1,1,4,2,1,1,0,0]。
提示:
气温列表长度的范围是
[
1
,
30000
]
[1, 30000]
[1,30000]。每个气温的值的均为华氏度,都是在
[
30
,
100
]
[30, 100]
[30,100] 范围内的整数。
思路:
- 把数组的元素想象成并列站立的人,元素大小想象成人的身高。这些人面对你站成一列,如何求元素 「 2 」 「2」 「2」的 Next Greater Number 呢?很简单,如果能够看到元素 「 2 」 「2」 「2」,那么他后面可见的第一个人就是 「 2 」 「2」 「2」的 Next Greater Number,因为比 「 2 」 「2」 「2」小的元素身高不够,都被 「 2 」 「2」 「2」挡住了,第一个露出来的就是答案。
- 使用单调递减栈,即从栈顶开始,自顶向下,上面的数据不大于其下的数据。将数据依次从头至尾进行压栈操作,若是栈不为空,且栈顶元素小于所遍历到的元素,则认为找到了栈顶元素之后第一个更高的气温,将当前所遍历元素的索引值减去存于栈中的栈顶索引值,即可得到栈顶元素位置想要观测到更高的气温所需等待的天数。
进行如上出栈操作直至栈顶元素索引所指向的温度值大于当前所遍历的元素为止,然后将当前元素压入栈中,继续进行数组的遍历。
代码:
vector<int> dailyTemperatures(vector<int>& T) {
vector<int> ans(T.size());
stack<int> s; // 这里放元素索引,而不是元素
for (int i = T.size() - 1; i >= 0; i--) {
while (!s.empty() && T[s.top()] <= T[i]) {
s.pop();
}
ans[i] = s.empty() ? 0 : (s.top() - i); // 得到索引间距
s.push(i); // 加入索引,而不是元素
}
return ans;
}
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
vector<int> dist(T.size(), 0);
stack<int> descendStack;
for(int i = 0; i < T.size(); i++) {
while(!descendStack.empty() && T[i] > T[descendStack.top()]) {
int targetDay = descendStack.top();
descendStack.pop();
dist[targetDay] = i - targetDay;
}
descendStack.push(i);
}
return dist;
}
};
503. 下一个更大元素 II
题目描述:
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字
x
x
x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出
−
1
-1
−1。
示例:
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
思路:
与739. Daily Temperatures (Medium)
不同的是,数组是循环数组,并且最后要求的不是距离而是下一个元素。由于是循环数组,所以每个元素都需要进行两次压栈操作。具体的:
此外,计算机的内存都是线性的,没有真正意义上的环形数组,但可模拟出环形数组的效果,一般是通过 %
求模,获得环形的遍历结构。之后将原始数组复制并拼接,就是在后面再接一个原始数组,以实现元素与其左右两边元素进行比较。
代码:
/*version 1*/
vector<int> nextGreaterElements(vector<int>& nums) {
int n = nums.size();
vector<int> res(n); // 存放结果
stack<int> s;
// 假装这个数组长度翻倍了
for (int i = 2 * n - 1; i >= 0; i--) {
while (!s.empty() && s.top() <= nums[i % n])
s.pop();
res[i % n] = s.empty() ? -1 : s.top();
s.push(nums[i % n]);
}
return res;
}
/*version 2*/
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int length = nums.size();
vector<int> nextBiggerElement(length, -1);
stack<int> descendStack;
for(int i = 0; i < length*2; i++) {
int num = nums[i%length];
while(!descendStack.empty() && nums[descendStack.top()] < num) {
nextBiggerElement[descendStack.top()] = num;
descendStack.pop();
}
if(i < length) descendStack.push(i);
}
return nextBiggerElement;
}
};
42. 接雨水
解决方案https://blog.csdn.net/yueguangmuyu/article/details/112180954。