目录
单调栈
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。时间复杂度为O(n)。
单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优点是整个数组只需要遍历一次。
使用单调栈主要有三个判断条件。
- 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
- 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
- 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况
题目链接:739. 每日温度
思路
求右边比自己大的元素与自己的距离,使用单调栈,从栈头到栈底单调递增,首先将遍历的第一个元素入栈,然后分析三种情况,小于,等于和大于。PS:栈保存的是下标,而非元素,这样便于记录距离
①当前元素 > 栈头:记录距离保存到result数组中,距离=当前下标-栈头,栈头元素出栈,出栈后继续比较,直至小于等于或者栈空时当前元素入栈,
②当前元素 < 栈头:入栈,不更新距离
③当前元素 = 栈头:入栈,不更新距离
代码
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> st; // 递增栈
vector<int> result(temperatures.size(), 0); // 记录距离,初始化全部为0
st.push(0);
for (int i = 1; i < temperatures.size(); i++) {
if (temperatures[i] <= temperatures[st.top()]) {
st.push(i);
} else {
while (!st.empty() &&
temperatures[i] > temperatures[st.top()]) {
result[st.top()] = i - st.top();
st.pop();
}
}
st.push(i);
}
return result;
}
};
题目链接:496.下一个更大元素 I
思路
与739.每日温度类似,只不过是在另一个数组中寻找更大元素。判断nums2[i]是否在nums1中是否出现过,而且又没有重复元素,所以使用哈希表,unordered_map可以表示映射关系可以通过数值快速找到下标。依旧是三种情况:
①小于,直接入栈
②等于,直接入栈
③大于,判断哈希表中能否找到对应元素,如果找到,则更新result数组,index为查询到对应元素的下标,result[index] = nums2[i]
代码
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
stack<int> st;
vector<int> result(nums1.size(), -1);
// 如果nums2只有一个元素,就不存在下一个更大的元素
if (nums2.size() == 1)
return result;
unordered_map<int, int> umap; // 创建map
// 将nums1的元素和对应下标存到map中
for (int i = 0; i < nums1.size(); i++) {
umap[nums1[i]] = i;
}
st.push(0); // 第一个下标0入栈
for (int i = 1; i < nums2.size(); i++) {
// 小于等于,直接入栈
if (nums2[i] <= nums2[st.top()]) {
st.push(i);
}
// 大于时
else {
while (!st.empty() && nums2[i] > nums2[st.top()]) {
// 当前元素大于栈头元素,如果在map中找到栈头元素
// 说明找到了下一个更大元素,将这个元素存到result中
if (umap.count(nums2[st.top()]) > 0) {
// 栈中存的是下标
// nums2[st.top()]表示该下标在数组中对应的元素
// umap[nums2[st.top()]]表示上述元素在哈希表中对应的下标
int index = umap[nums2[st.top()]];
result[index] = nums2[i];
}
st.pop();
}
st.push(i);
}
}
return result;
}
};
总结
①单调栈解决的问题是找右边比自己大或者小的元素,如果找比自己大的元素就是用递增栈,如果找比自己小的元素就用递减栈
②单调栈存的是下标,如果比较元素则利用下标索引元素值
③单调栈一般先将第一个下标0入栈
④遍历数组是从下标1开始,进行比较
⑤遍历数组时有三种情况,小于,等于,大于,今天这两道题都是找比自己大的元素,所以小于等于直接入栈;大于时,要保证栈从栈头到栈底单调递增,所以需要将栈头元素弹出,直至当前元素大于栈头元素或者栈为空时,将当前元素入栈
⑥当前元素大于栈头时,如果要计算距离,就要用当前元素的下标减去栈头,栈头保存的也是下标,所以差值就是距离,这个距离也要保存到栈头这个下标所对应的结果数组中
⑦一定要先计算距离,再进行pop操作
⑧大于时的循环操作结束后,要将当前元素的下标入栈