LeetCode 題號739中等難度 每日溫度
題目描述:
根據每日 氣溫 列表,請重新生成一個列表,對應位置的輸入是你需要再等待多久溫度才會升高超過該日的天數。如果之后都不會升高,請在該位置用 0 來代替。
例如,給定一個列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的輸出應該是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:氣溫 列表長度的范圍是 [1, 30000]。每個氣溫的值的均為華氏度,都是在 [30, 100] 范圍內的整數。
雖說這是一個中等難度的題目,但看完題目后會發現其實要做出來其實不困難,甚至可以說有點簡單(單純的為了AC)
很簡單,題目要求就是給一個數組,讓你返回一個數組,新數組對應位置表示的是題目給的數組對應位置往后找第一個值比其大的位置距離,如果沒有則為0;
直接簡單循環遍歷就可以通過了。
1 class Solution { 2 public int[] dailyTemperatures(int[] T) { 3 int[] ans = new int[T.length]; 4 for(int i = 0 ; i < T.length-1;i++){ 5 ans[i] = 0 ; 6 for(int j = i+1;j<T.length;j++){ 7 if(T[j]>T[i]){ 8 ans[i] = j-i; 9 break; 10 } 11 } 12 } 13 return ans; 14 } 15 }
這樣子就可以ac了,但是效率呢?
先上ac后截圖:
223ms- -,嚇死個人了。僅僅30%多而已。
在我看來,刷題第一個目標是為了ac,第二個目標是優化。
本人也是個渣渣,也不會優化- -。但是leetcode上有大牛- -。
多說無益直接上大牛代碼:
1 class Solution { 2 public int[] dailyTemperatures(int[] T) { 3 int length = T.length; 4 int[] result = new int[length]; 5 6 //從右向左遍歷 7 for (int i = length - 2; i >= 0; i--) { 8 // j+= result[j]是利用已經有的結果進行跳躍 9 for (int j = i + 1; j < length; j+= result[j]) { 10 if (T[j] > T[i]) { 11 result[i] = j - i; 12 break; 13 } else if (result[j] == 0) { //遇到0表示后面不會有更大的值,那當然當前值就應該也為0 14 result[i] = 0; 15 break; 16 } 17 } 18 } 19 20 return result; 21 } 22 }
看起來好像沒有什么變化好像只是菜雞小老弟我多了個幾行- -。
但是我們看看大佬代碼ac后的截圖
4ms,和菜雞我的200多ms 比起來我只是個弟中弟。
話不多說來分析一下大佬的精辟思想。
直接看核心代碼:
1 //從右向左遍歷 2 for (int i = length - 2; i >= 0; i--) { 3 // j+= result[j]是利用已經有的結果進行跳躍 4 for (int j = i + 1; j < length; j+= result[j]) { 5 if (T[j] > T[i]) { 6 result[i] = j - i; 7 break; 8 } else if (result[j] == 0) { //遇到0表示后面不會有更大的值,那當然當前值就應該也為0 9 result[i] = 0; 10 break; 11 } 12 } 13 } 14 15 作者:pulsaryu 16 鏈接:https://leetcode-cn.com/problems/daily-temperatures/solution/jie-ti-si-lu-by-pulsaryu/ 17 來源:力扣(LeetCode) 18 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
大佬習慣——代碼寫注釋。
可能有的人看完還不是很懂我們具體再分析一下。
首先,我們肯定要遍歷每一個數組元素的值的。那我們優化的點只能是在比較的過程。
回想題目要求,我們是要從當前位置往后面找第一個比該位置值大的位置與他的距離(其實就是下標的差);
然后把這個距離存進返回的數組對應的位置下標。
我們正常想都是從前往后遍歷。但是這題我們每次遍歷都得往后找。那我們可以嘗試着從后往前即從右往左啦。
再這個基礎上,再往后找。
這樣子的好處是我們往后找的時候,后方的位置都是已經計算好的。
如果我們的是從前往后遍歷,那我們比較永遠只能一個位置一個位置都比較找到第一個值大的位置則為止繼續找下一個位置。
如果我們已經算好后方的位置呢?
看下大佬的圖文:
71的位置對應值2,表明71的后面的的第二個元素就是第一個比71大的位置。
這樣子我們就可以跳躍。我們求75位置。往后找的時候,如果后方的比當前位置小,那們我們沒有必要j++這樣子一個一個看,我們可以直接
根據后方元素的值即result[j]跳躍,我們不用j++;我們可以直接j = j+ result[j];再與75比較如果比75大則返回索引差。
如果后方位置的值 比當前位置小並且result[j]==0代表什么呢?就是代表 j 位置 后方的都沒有j 位置的大。而當前位置又比J位置的大。那當前位置
往后找也找不出一個比其大的位置 所以 直接result[i] = 0;
每一次計算出當前位置的值后我們就直接break 掉內層循環 然后接着遍歷前一個元素即可.
其實這種跳躍思想有點像 字符串模式匹配用到的KMP算法next數組的思想。
如果不知道KMP是什么的可以點下方連接學習
https://blog.csdn.net/sinat_37537673/article/details/73331135
本人只是個普通二本在讀大二的菜雞,只是個搬運工,不喜勿噴- -。