題目描述
請根據每日 氣溫 列表,重新生成一個列表。對應位置的輸出為:要想觀測到更高的氣溫,至少需要等待的天數。如果氣溫在這之后都不會升高,請在該位置用 0 來代替。
例如,給定一個列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73]
,你的輸出應該是[1, 1, 4, 2, 1, 1, 0, 0]
。
這個輸出我看了半分鐘才看明白,可能需要解釋一下:
從第0天開始,第1天的溫度比它高,意思就是第0天需要等待1天就能觀測到更高的氣溫,所以下標0填1。
第2天溫度比第1天高,則第1天同樣僅需等待1天就能觀測到更高到氣溫,所以下標1也填1。
第2天的溫度是75,往后第3,4,5天的溫度都低于第2天,到了第6天溫度才高于第2天,所以第2天需要等待4天才能觀測到更高氣溫,下標2填4。
第6天的溫度是76,往后的每一天的溫度都比它低,也就是等不到能觀測到比第6天更高氣溫的那天,按題目要求填0.
第7天是最后一天,沒有參照物比較,也填0.
最后正確的輸出就應該是:[1, 1, 4, 2, 1, 1, 0, 0]
提示:氣溫 列表長度的范圍是 [1, 30000]。每個氣溫的值的均為華氏度,都是在 [30, 100] 范圍內的整數。
方法一:暴力解法
思路:
這個題目簡單理解就是對于位置i,找到位置j,位置j是滿足:
j > i
temperatures[j] > temperatures[i]
兩個條件的最小下標。
所以對于每個位置,都從該位置+1的地方往后遍歷,找到第一個大于它的值,計算兩個下標差值即可。
代碼:
var dailyTemperatures = function(temperatures) {
let len = temperatures.length
if(len <= 0) return []
let res = []
// 最后一個元素后面一定沒有比它大的值
res[len-1] = 0
for(let i = len-2; i >= 0; i--) {
let target = temperatures[i]
for(let j = i+1; j < len; j++) {
let current = temperatures[j]
if(current > target) {
res[i] = j-i
break;
}
}
// 這里的意思是該位置后面沒有出現過比它大的值
if(res[i] === undefined) {
res[i] = 0;
}
}
return res;
};
性能:
時間復雜度:O(n^2)
空間復雜度:O(n)
方法二:單調棧
單調棧就是棧中的元素滿足單調遞增或遞減。
思路:
如果相鄰位置的兩個數,前一個數小于后一個數,則很明顯,前一個位置的結果就是1,即只需要等待一天。
如果前一個數大于后一個數,則前一個位置的結果不能確定,需要指針繼續向后走,直到一個比它大的數出現,才能知道其需要等待的天數。
也就是說,對于每個位置來說,都只需要找到往后最小的下標,滿足其氣溫高于當前位置。
對于暫時還未找到更高氣溫的位置,存入棧中,指針每一次向后移動時,和棧中元素比較,如果發現更高,表示棧中存放的元素可以確定等待天數了,則該元素出棧。
按這個思路你會發現,能存入棧中的元素,滿足一個條件:棧中元素是遞減的(從棧底到棧頂),不會存在新入棧的元素比棧頂元素更大的情況,因為這種情況下,棧頂元素就直接出棧了(已經找到了等待天數自然就不會呆在棧中了)
當棧頂元素出棧后,棧頂變成了之前的第二位元素,此時,新棧頂元素和指針指向的元素大小關系如何呢?比較一下就知道了,如果新棧頂元素也能出棧,則繼續比較,直到棧空。如果不能出棧,將指針指向元素推入棧中,指針繼續向后移動。
好了,這就是解題思路了。
來個例子理解一下。
溫度列表:temperatures = [73, 74, 75, 71, 69, 72, 76, 73]
指針:p = 0
單調棧:stack = []
結果: res = []
p=0
時,棧空,0直接入棧, stack=[0]
p=1
時,棧頂值是0,temperatures[1]
大于temperatures[0]
,0出棧,同時res[0] = 1-0
, 此時棧空,1直接入棧, stack=[1]
p=2
同理,res[1] = 2-1
, stack=[2]
p=3
時, 棧頂值是2,temperatures[3]
小于temperatures[2]
,3入棧, stack=[2, 3]
p=4
時,棧頂值是3,temperatures[4]
小于temperatures[3]
,4入棧,stack=[2, 3, 4]
p=5
時,此時棧中元素如下:
棧頂值是4,
temperatures[5]大于temperatures[4]
,4可以出棧,同時res[4] = 5-4
,此時棧中還有元素,棧頂值變成3,繼續比較。
temperatures[5]
大于temperatures[3]
,3可以出棧,同時res[3] = 5-3
,此時棧中還有元素,棧頂值變成2,繼續比較。temperatures[5]
小于temperatures[2]
,5入棧,stack=[2, 5]
p=6
時,棧頂值是5,temperatures[6]
大于temperatures[5]
,5出棧,同時res[5] = 6-5
, 此時棧中還有元素,棧頂值變成2,繼續比較。
temperatures[6]
大于temperatures[2]
,2出棧,同時res[2] = 6-2
, 此時棧空,6直接入棧。
p=7
時,temperatures[7]
小于temperatures[6]
,7入棧,stack=[6, 7]
p=8
時,越界,退出循環。
此時棧中還有兩個元素,它們的等待天數也還是未知的,不過這里稍微想一想就能發現,這兩個元素,都是沒有找到更高氣溫的,所以等待天數為0.
代碼:
var dailyTemperatures = function(temperatures) {
let stack = []
let res = []
for(let i = 0, len = temperatures.length; i < len; i++) {
while(stack.length && temperatures[stack[stack.length-1]] < temperatures[i]) {
let j = stack.pop()
res[j] = i-j
}
stack.push(i)
}
//最后棧內存在的元素代表的是在該位置后沒有比它更大的值,所以都填0
while(stack.length) {
res[stack.pop()] = 0
}
return res
}
性能:
時間復雜度:O(n)
(不太明白for
循環中嵌套了while
循環為什么還是O(n)
,知道的小伙伴評論里求解答)
空間復雜度:O(n)