目录
讀題
739. 每日温度
自己看到题目的第一想法
就是用每個數去遍歷後面的數,但超時了,程式碼如下。
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
vector<int> highTemp(temperatures.size(), 0);
for(int i = 0; i < temperatures.size(); i++) {
int high = 0;
highTemp[i] = high;
for(int j = i + 1; j < temperatures.size();j++) {
if(temperatures[i] > temperatures[j]) high++;
else {
high++;
highTemp[i] = high;
break;
}
}
}
return highTemp;
}
};
看完代码随想录之后的想法
單調棧,就是當要尋找一個元素左邊或者右邊第一個比自己大的元素位置,就可以考慮使用單調棧。
其本質是使用空間換時間,在遍歷的過程中使用棧來記錄右邊比當前元素高或低,優點就是数組只需要遍歷一次
使用單調棧時需要明確
- 單調棧裡存放的元素是甚麼
- 單調棧是遞增還是遞減,(順序方面因人而異,以我來說,就是跟著卡哥的順序,從棧頂到棧底,逐步遞增或遞減)
每日溫度就是一個單調棧很經典的題目,右邊第一個比自己大的元素在甚麼時候。
單調棧存放的元素是數組下標,方便在results数組中進行計算。
單調棧是遞增,可以想像假設當前元素比棧頂大,為了維持單調棧,就需要pop出來,棧頂元素就是右邊第一個比較大的元素就是當前元素。
看完卡哥的講解後對於單調棧就比較清晰了。
496.下一个更大元素 I
自己看到题目的第一想法
第一瞬間其實就想到這個只是繞一個彎,一樣單調棧是放数組下標,但是在遍歷nums2的過程中,紀錄當前元素有沒有跟nums1相同的數值,如果相同,則紀錄nums2的下標為多少到result2,其他部分一樣是製作出一個右邊第一個比自己大的元素的数組result。
之後再遍歷result2的数組,將results裡面有result2的位置讀取,假設不是-1,則將result2的值,改為nums2的當下數值加上比這個元素大的數值是後面第幾個出現的。
看完代码随想录之后的想法
看完之後才知道我想得很複雜,其實可以使用map,nums1的數值當作key,下標當作value,在遇到右邊第一個比較大的元素時,判斷nums1有沒有nums2[st.top()]的數值,如果有則將利用map快速找到nums1的對應下標使用nums2的當前元素更新results數組。之前沒有想過這樣的解法。
739. 每日温度 - 實作
思路
-
單調棧存放的元素
數組下標
-
單調棧性質 - 遞增 (棧頂到棧底)
-
當 棧頂大於等於當前數值時,儲存當前数組的下標到單調棧
-
當 棧頂小於當前數值時,代表找到第一個比較大的元素。
- while循環,值到棧為空或者棧頂大於等於當前數值
- results[st.top()] = i - st.top() → st.top 是原數組下標,跟results数組是對應的,至於i - st.top() 代表棧頂的位置跟當前元素的距離為和
- 將棧頂元素pop出來
- while循環,值到棧為空或者棧頂大於等於當前數值
-
return results數組。
Code
清晰版
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> st;
vector<int> results(temperatures.size(), 0);
st.push(0);
for(int i = 1; i < temperatures.size(); i++) {
if(temperatures[st.top()] >= temperatures[i]) {
st.push(i);
} else {
while(!st.empty() && temperatures[st.top()] < temperatures[i]) {
results[st.top()] = i - st.top();
st.pop();
}
st.push(i);
}
}
return results;
}
};
精簡版
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> st;
vector<int> results(temperatures.size(), 0);
st.push(0);
for(int i = 1; i < temperatures.size(); i++) {
while(!st.empty() && temperatures[st.top()] < temperatures[i]) {
results[st.top()] = i - st.top();
st.pop();
}
st.push(i);
}
return results;
}
};
496.下一个更大元素 I - 實作
思路
原思路
- 建立兩個數組
- result 紀錄nums2的每個數值右邊第一個最大元素
- result2 紀錄 nums1 在 nums2 的位置
- 遍歷nums2的過程中,紀錄當前元素有沒有跟nums1相同的數值,如果相同,則紀錄nums2的下標為多少到result2
- 使用單調棧更新result数組
- 遍歷result2數組
- results裡面有result2的位置讀取,假設不是-1,則將result2的值,改為nums2的當下數值加上比這個元素大的數值是後面第幾個出現的
- 不是則更新為-1
- return result2數組
代碼隨想錄思路
- 建立map紀錄nums1的數值與下標映射關係
- key = nums1數值
- value = nums1對應下標。
- 遇到右邊第一個比較大的元素時
- 判斷map中是否有對應的nums2的棧頂下標所映射到的數值
- 如果有則將利用map快速找到nums1的對應下標使用nums2的當前元素更新results數組
Code
原思路
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
stack<int> st;
vector<int> results(nums2.size(), -1);
vector<int> results2(nums1.size(), -1);
for(int i = 0; i < nums2.size(); i++) {
for(int j = 0; j < nums1.size(); j++) {
if(nums1[j] == nums2[i]) {
results2[j] = i;
break;
}
}
while(!st.empty() && nums2[st.top()] < nums2[i]) {
results[st.top()] = i - st.top();
st.pop();
}
st.push(i);
}
for(int k = 0; k < nums1.size(); k++) {
int temp = results2[k];
if(results[temp] != -1) results2[k] = nums2[temp + results[temp]];
else results2[k] = results[temp];
}
return results2;
}
};
代碼隨想錄思路
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
stack<int> st;
vector<int> results(nums1.size(), -1);
unordered_map<int, int> umap;
for (int i = 0; i < nums1.size(); i++) {
umap[nums1[i]] = i;
}
for(int i = 0; i < nums2.size(); i++) {
while(!st.empty() && nums2[st.top()] < nums2[i]) {
if(umap.count(nums2[st.top()]) > 0) {
results[umap[nums2[st.top()]]] = nums2[i];
}
st.pop();
}
st.push(i);
}
return results;
}
};
總結
自己实现过程中遇到哪些困难
第一次理解單調棧的題目,在理解上花了比較長的時間,並且自己對於map的使用不太熟悉,所以在第二題時,想到了更繞的解法。
今日收获,记录一下自己的学习时长
今天大概學習2hr,主要是去理解單調棧的思維,理解不難,但是在實踐過程中需要多練習。
相關資料
● 今日学习的文章链接和视频链接
739. 每日温度
https://programmercarl.com/0739.每日温度.html