写在前面:
什么时候用单调栈:要给当前的元素,找右边/左边第一个比它大/小的位置。
题目:
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
解题思路:
方法1: 暴力
方法2: 单调栈
本题明显符合要给当前的元素找右边第一个比他大的位置。
维护一个单调递减的栈,存放温度数组的序号;
正向遍历所有温度值,当该序号A的温度大于栈顶序号B指向的温度时,则计算该序号A的等待天数;
当该序号A的温度小于栈顶序号B指向的温度时,入栈。
int* dailyTemperatures(int* T, int TSize, int* returnSize){
int* res = calloc(TSize+1, sizeof(int));
int i;
//特殊处理
for (i = 0; i < TSize-1; i++)
{
int j = i+1;
if (T[i] < T[j])
{
res[i]++;
continue;
}
while (j < TSize)
{
if (T[i] < T[j]) {
res[i]++;
break;
}
res[i]++;
//边界控制
if (j == TSize - 1 && T[i] >= T[j]) {
res[i] = 0;
}
j++;
}
}
res[i] = 0;
*returnSize = i+1;
return res;
}
//单调栈
/**
* Note: The returned array must be malloced, assume caller calls free().
1. 申请数组,初始值为0;
2. 单次遍历;
3. 寻找更大的温度index的差值,从左到右维护一个单调递增的栈
所以存入的值为index - stack[top];而不是出栈的元素值;T[stack[top]]
*/
#define LEN 30000
int* dailyTemperatures(int* T, int TSize, int* returnSize)
{
int* res = calloc(TSize, sizeof(int));
memset(res, 0, sizeof(int) * TSize);
int* stack = calloc(LEN, sizeof(int));
int top = -1;
for (int i = 0; i < TSize; i++) {
int index = i;
//栈不为空,且元素大于栈顶元素 出栈 stack[top]为出栈的栈顶元素 index
while (top > -1 && T[index] > T[stack[top]]) {
res[stack[top]] = index - stack[top];//理解这行 stack[top]为出栈元素的index, index为当前取到的元素index
top--;
}
//入栈 更新栈顶元素
stack[++top] = index;
}
*returnSize = TSize;
return res;
}
class Solution {
public int[] dailyTemperatures(int[] T) {
//special
int lenT = T.length;
if (T == null || lenT == 0) {
return null;
}
//normal
//新建数组,遍历所有数值,当大于栈顶元素时,计算栈顶元素位置所填的值
//小于栈顶元素时入栈
Deque<Integer> s = new ArrayDeque<>();
//如果使用LinkedList类,可以直接使用pop 和 push方法
//Deque<Integer> s = new LinkedList<>();
int[] list = new int[lenT];
for (int i = 0; i < lenT; i++) {
//出栈
while (!s.isEmpty() && (T[i] > T[s.peekLast ()])) {
int bottom = s.pollLast ();
list[bottom] = i - bottom;
}
//入栈
s.addLast(i);
}
return list;
}
}