0%

Leetcode - 739. 每日温度

Description

根据每日 气温 列表,请重新生成一个列表,对应位置的输出是需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。

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

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

Solution

这一题的本质是,找到a[i]右边第一个比它大的元素,并且返回二者下标的差值。

蛮力算法

蛮力算法思路很好想,遍历嘛。找到右侧第一个大于a[i]的,就结束循环。
蛮力算法虽然时间复杂度并不能满足要求,但至少可以保证正确性。可以利用蛮力算法做一个对照,来调试其他算法的正确性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
stack<int> S;
vector<int> temp(T.size(),0);
for (int i=0; i<T.size(); i++) {
for (int j=i+1; j<T.size(); j++) {
if (T[i]<T[j]) {
temp[i] = j-i;
break;
}
}
}
return temp;
}
};

单调栈

这个题跟直方图中最大矩形是同类型的题,甚至要更简单一点。利用一个辅助栈,如果当前元素大于栈顶元素,计算下标差值,然后弹出栈顶元素。如果当前元素小于等于栈顶元素,入栈。这个方法的时间复杂度是O(n),每个元素入栈出栈各一次。

一个手动运行样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
数组 1 5 2 4 3 6             结论 1 4 1 2 1 0
下标 0 1 2 3 4 5
结果 0 0 0 0 0 0

辅助栈 结果数组
0 0 0 0 0 0 0
1 1 0 0 0 0 0
1 2 1 0 0 0 0 0
1 1 0 1 0 0 0
1 3 1 0 1 0 0 0
1 3 4 1 0 1 0 0 0
1 3 1 0 1 0 1 0
1 1 0 1 2 1 0
null 1 4 1 2 1 0
6 1 4 1 2 1 0

我这个样例里没有考虑元素相等的情况,如果想不明白可以自己举个例子试一试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
stack<int> S;
vector<int> temp(T.size(),0);

for (int i=0; i<T.size(); i++) {
while (!S.empty()&&T[S.top()]<T[i]) {
temp[S.top()] = i-S.top();
S.pop();
}
S.push(i);
}
return temp;
}
};

https://leetcode-cn.com/problems/daily-temperatures

我自己的思考过程

辅助栈不存温度,存下标(有利于更新)
栈中下标所对应元素必然单调递减
辅助数组每层循环都更新
栈空的时候,元素入栈
无论元素是否出栈,都需要+1,因为找到所需元素的位置,至少需要右移一位。
判断当前元素和栈顶元素的关系,如果当前元素大于栈顶元素,弹出栈顶元素的位置,过程持续到当前元素小于等于(不大于)栈顶元素。此时当前元素入栈。

优化更新,直接利用下标相减
根据蛮力算法,找出问题的本质是找到a[i]右边第一个比它大的元素,并且返回二者下标的差值。

小结:
坚持从蛮力算法入手,比较容易看清问题的本质,少走弯路。不过在边界情况的考虑上有所进步~冲鸭🎉