如果需要找到左边或者右边第一个比当前位置的数大或者小,则可以考虑使用单调栈
单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个元素比当前的元素,优点是只需要遍历一次
从前往后遍历温度数组temperatures[i],
若栈为空,则将i入栈;
若栈不为空,则将栈顶元素对应的温度与当前温度对比,
如果当前温度大于栈顶元素对应的温度,那么将栈顶下标对应的等待天数赋值为当前温度下标减栈顶下标,将栈顶元素移除,再将当前温度下标入栈;
如果当前温度小于等于栈顶元素对应温度,则将当前温度下标入栈。
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> st;
vector<int> result(temperatures.size(), 0);
st.push(0); //此时栈为空,下标0直接入栈
for (int i = 1; i < temperatures.size(); i++) {
if (temperatures[i] < temperatures[st.top()]) st.push(i); //当前温度 小于 栈顶元素对应的温度 直接入栈
else 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;
}
};
代码优化后:
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> st;
vector<int> result(temperatures.size(), 0);
for (int i = 0; i < temperatures.size(); i++) {
while (!st.empty() && temperatures[i] > temperatures[st.top()]) {
result[st.top()] = i - st.top();
st.pop();
}
st.push(i);
}
return result;
}
};
同样维护一个单调栈,从栈顶到栈底的元素是单调递增的
从前往后遍历nums2[i],
若栈为空,则将i入栈;
若栈不为空,则将遍历到的元素nums2[i]与栈顶元素nums2[st.top()]对比:
如果当前遍历到的元素 小于 栈顶元素,则满足栈递增(从栈顶到栈底),直接入栈;
如果当前遍历到的元素 等于 栈顶元素,因为求的是右边第一个比当前元素大的元素,也直接入栈;
如果当前遍历到的元素 大于 栈顶元素,此时若入栈则不满足栈递增,遍历到的元素就是右边第一个当前元素(栈顶元素)大的元素,再判断栈顶元素是否在nums1中出现过,如果出现过,记录当前遍历到的元素。然后将栈顶元素弹出,遍历到的元素入栈。
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
stack<int> st;
vector<int> result(nums1.size(), -1); //如果不存在则对应位置输出-1,因此全部初始化为-1
if (nums1.size() == 0) return result;
unordered_map<int, int> umap; //key:nums1中的元素,value:下标
for (int i = 0; i < nums1.size(); i++) {
umap[nums1[i]] = i;
}
st.push(0);
for (int i = 1; i < nums2.size(); i++) {
if (nums2[i] < nums2[st.top()]) st.push(i); //当前遍历到的元素 小于 栈顶元素
else if (nums2[i] == nums2[st.top()]) st.push(i); //当前遍历到的元素 等于 栈顶元素
else { //当前遍历到的元素 大于 栈顶元素
while (!st.empty() && nums2[i] > nums2[st.top()]) {
if (umap.count(nums2[st.top()]) > 0) { //查找map李是否存在这个元素,count(key):在容器中查找以 key 键的键值对的个数
int index = umap[nums2[st.top()]]; //根据map找到num2[st.top()]在nums1中的下标
result[index] = nums2[i]; //根据nums1元素的下标来更新result数组
}
st.pop();
}
st.push(i);
}
}
return result;
}
};
也可以像上一题那样简化:
class Solution {
public:
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;
}
};
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
vector<int> result(nums.size(), -1);
if (nums.size() == 0) return result;
stack<int> st;
for (int i = 0; i < nums.size() * 2; i++) {
// 模拟遍历两边nums,注意一下都是用i % nums.size()来操作
while (!st.empty() && nums[i % nums.size()] > nums[st.top()]) {
result[st.top()] = nums[i % nums.size()];
st.pop();
}
st.push(i % nums.size());
}
return result;
}
};