LeetCode 739. Daily Temperatures
分析过程
由题意,对于给出数组中的每个数,找出下一个距离最近的、比它大的数,并计算它们下标的间隔,没有的话标记为 0。
解法一
暴力枚举。通过双重 for 循环,从每一个数字开始,往后遍历,直至找到比该数字大的数,计算下标。
这种解法,对于递增的数组来说,计算速度是快的,时间复杂度约为
O
(
N
)
O(N)
O(N)。但对于类似 [50, 49, 48, 47, 46, 45, 51]
的数组,时间复杂度会升高到
O
(
N
2
)
O(N^2)
O(N2)。大量的计算被浪费在不必要的比较中。
解法二(推荐)
优化裁剪解法一中不必要的计算是解题的关键。若有以下命题:
命题一:a > b;
命题二:b > c;
命题三:a > c;
命题四:c < d;
命题五:a < d。
若命题一、二为真,可推断出命题三为真。而命题四为真,无法推断出命题五为真。套用入该题的语境中,仅有相邻数字和潜在答案可能性的两个数字之间,才有比较的必要。上述命题中的命题三,在该约束条件下,就没有进行比较的必要了。(非数学专业,上面的推理若有错误,还望指正。)
对于这种场景,可以使用单调栈(Monotonic Stack)来优化算法。当单调栈为空或栈顶数字大于等于当前数字时,将当前数字压入栈;当栈非空且栈顶数字比当前数字小时,弹出栈顶的数字并计算保存下标。由于该题需要计算的是两数字的间隔,仅需将下标压入栈即可。
代码实现为:
public int[] dailyTemperatures(int[] temperatures) {
int len = temperatures.length;
int[] res = new int[len];
Deque<Integer> deque = new ArrayDeque<>();
for (int currIndex = 0; currIndex < len; currIndex++) {
while (!deque.isEmpty() && temperatures[deque.peek()] < temperatures[currIndex]) {
int prevIndex = deque.pop();
res[prevIndex] = currIndex - prevIndex;
}
deque.push(currIndex);
}
return res;
}