代码随想录算法训练营day58|第十章 单调栈part01
目录
739. 每日温度
今天正式开始单调栈,这是单调栈一篇扫盲题目,也是经典题。大家可以读题,思考暴力的解法,然后在看单调栈的解法。 就能感受出单调栈的巧妙
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。
单调栈里只需要存放元素的下标i就可以了,如果需要使用对应的元素,直接T[i]就可以获取。单调递增指的是栈顶到栈底的方向上是单调递增的,如果求一个元素右边第一个更大元素,单调栈就是递增的,如果求一个元素右边第一个更小元素,单调栈就是递减的。
如图所示,一旦遍历到的元素大于栈顶元素,那就没办法维持顺序(从栈顶到栈底单调递增了),所以想要放入当前元素,需要将栈顶元素弹出,直到栈顶元素再也不小于当前遍历到的元素为止或栈为空,每弹出一个元素,在这道题中就相当于找到了之后比它温度大的一天,于是就要同步更新res数组记录二者的距离,这时候就凸现出单调栈存入下标的必要性了,这样可以直接操作对应下标的res值,等于当前遍历到的元素下标减去弹出的下标。
vector<int> dailyTemperatures(vector<int>& T) {
stack<int> st; // 递增栈
vector<int> result(T.size(), 0);
for (int i = 0; i < T.size(); i++) {
while (!st.empty() && T[i] > T[st.top()]) { // 注意栈不能为空
result[st.top()] = i - st.top();
st.pop();
}
st.push(i);
}
return result;
}
文章中说这种做法更能体现实质,但是我觉得实际上是有些麻烦的,只要搞清楚要维护单调栈单调递增的逻辑即可,单调递增所以必然遇到大于顶部元素的情况才会处理。
vector<int> dailyTemperatures(vector<int>& T) {
// 递增栈
stack<int> st;
vector<int> result(T.size(), 0);
st.push(0);
for (int i = 1; i < T.size(); i++) {
if (T[i] < T[st.top()]) { // 情况一
st.push(i);
} else if (T[i] == T[st.top()]) { // 情况二
st.push(i);
} else {
while (!st.empty() && T[i] > T[st.top()]) { // 情况三
result[st.top()] = i - st.top();
st.pop();
}
st.push(i);
}
}
return result;
}
496.下一个更大元素 I
本题和 739. 每日温度 看似差不多,其实 有加了点难度。
这道题我和文章里面的做法稍有不同,但同样是使用了上一道题的思路加上unordered_map来收集结果,都很容易理解。
我的做法——
我的做法是先处理nums2数组,求出每一个的结果(弹出时为收集真正结果的时候,但是当前遍历到的元素也要有一个初始值-1,防止nums1中的数在map中没有结果)(其实初始化res的时候设置为-1没有用到),用map键值对记录(键为nums2[ st.top() ]的数值,值为找到的最近较大值),这样只需要遍历一遍nums1就可以通过map找到对应结果。
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
stack<int> st;
st.push(0);
vector<int> res(nums1.size(),-1);
unordered_map<int,int> m;
m[nums2[0]]=-1;
for(int i=1;i<nums2.size();i++){
while(st.size()&&nums2[i]>nums2[st.top()]){
m[nums2[st.top()]]=nums2[i];
st.pop();
}
st.push(i);
m[nums2[i]]=-1;
}
for(int i=0;i<nums1.size();i++){
res[i]=m[nums1[i]];
}
return res;
}
文章里面的做法——
文章里面的做法是用map来记录nums1里面每一个数值对应的下标,这样每在nums2中找到结果的时候,就可以通过count函数来判断这个值是否在nums1里面存在,如果存在就获取它在nums1里面对应的下标,然后记录找到的数值到res数组里面,注意这回res数组的初始化为-1有用到的。
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
stack<int> st;
vector<int> result(nums1.size(), -1);
if (nums1.size() == 0) return result;
unordered_map<int, int> umap; // key:下标元素,value:下标
for (int i = 0; i < nums1.size(); i++) {
umap[nums1[i]] = i;
}
st.push(0);
for (int i = 1; i < nums2.size(); i++) {
while (!st.empty() && nums2[i] > nums2[st.top()]) {
if (umap.count(nums2[st.top()]) > 0) { // 看map里是否存在这个元素
int index = umap[nums2[st.top()]]; // 根据map找到nums2[st.top()] 在 nums1中的下标
result[index] = nums2[i];
}
st.pop();
}
st.push(i);
}
return result;
}