503. 下一个更大元素 II
难度中等331
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
注意: 输入数组的长度不会超过 10000。
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int n = nums.size();
vector<int> ans(n, -1);
stack<int> stk;
//从后往前找 只不过最后的n - 1数是用来模拟循环数组的
//2 * n - 1是n + n - 1,n - 1是前n - 1个数
for(int i = 2 * n - 1; i >= 0; -- i){
//构造一个严格单调递减的栈,每次入栈时,比它小的数都会被剔除
//相等的也得剔除掉,因为我们是求严格更大的,所以必须加上>=
while(!stk.empty() && nums[i % n] >= stk.top()){
stk.pop();
}
//如果没找到更小的元素,那么就说明不存在
//i % n是用来表示循环数组
ans[i % n] = stk.empty() ? -1 : stk.top();
//加入比较行列
stk.push(nums[i % n]);
}
return ans;
}
};
84. 柱状图中最大的矩形
难度困难1220
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]
。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10
个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
int ans = 0;
vector<int> sl(n, -1), sr(n, n);
stack<int> stk;
//从暴力算法衍生,左右都找到最近的高度小于当前值的柱子
//求下一个最小,也就是往右看不满足条件的第一个值 即小于当前高度的最近值
//构造了一个单调递增栈 栈顶当前是最大 更大都被去掉了
for(int i = n - 1; i >= 0; -- i){
while(!stk.empty() && heights[i] <= heights[stk.top()]){
stk.pop();
}
sr[i] = stk.empty() ? n : stk.top();
stk.push(i);
}
while(!stk.empty()) stk.pop();
//求上一个最大,往左看不满足的第一个值
for(int i = 0; i < n; ++ i){
while(!stk.empty() && heights[i] <= heights[stk.top()]){
stk.pop();
}
sl[i] = stk.empty() ? -1 : stk.top();
stk.push(i);
}
for(int i = 0; i < n; ++ i){
int width = sr[i] - sl[i] - 1;
ans = max(ans, width * heights[i]);
}
return ans;
}
};
优化
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
int ans = 0;
vector<int> sl(n, -1), sr(n, n);
stack<int> stk;
//从暴力算法衍生,左右都找到最近的高度小于当前值的柱子
//求下一个最小,也就是往右看不满足条件的第一个值 即小于当前高度的最近值
//构造了一个单调递增栈 栈顶当前是最大 更大都被去掉了
for(int i = 0; i < n; ++ i){
while(!stk.empty() && heights[i] <= heights[stk.top()]){
sr[stk.top()] = i;
stk.pop();
}
sl[i] = stk.empty() ? -1 : stk.top();
stk.push(i);
}
for(int i = 0; i < n; ++ i){
int width = sr[i] - sl[i] - 1;
ans = max(ans, width * heights[i]);
}
return ans;
}
};
456. 132 模式
难度中等383
给你一个整数数组 nums
,数组中共有 n
个整数。132 模式的子序列 由三个整数 nums[i]
、nums[j]
和 nums[k]
组成,并同时满足:i < j < k
和 nums[i] < nums[k] < nums[j]
。
如果 nums
中存在 132 模式的子序列 ,返回 true
;否则,返回 false
。
进阶:很容易想到时间复杂度为 O(n^2)
的解决方案,你可以设计一个时间复杂度为 O(n logn)
或 O(n)
的解决方案吗?
示例 1:
输入:nums = [1,2,3,4]
输出:false
解释:序列中不存在 132 模式的子序列。
示例 2:
输入:nums = [3,1,4,2]
输出:true
解释:序列中有 1 个 132 模式的子序列: [1, 4, 2] 。
示例 3:
输入:nums = [-1,3,2,0]
输出:true
解释:序列中有 3 个 132 模式的的子序列:[-1, 3, 2]、[-1, 3, 0] 和 [-1, 2, 0] 。
提示:
n == nums.length
1 <= n <= 104
-109 <= nums[i] <= 109
class Solution {
public:
bool find132pattern(vector<int>& nums) {
stack<int> stk;
int k = INT_MIN;
int n = nums.size();
//保持单调栈是单调递减的
//也就是保持nums从后往前是单调递减的
//同时我们检测 因为不是单调递减而弹出一个j值,用一个k值来维护栈顶后的最大值
//只要往前的时候存在一个i值比k值小,而且k值还不在栈中,那么就满足条件
//i-1 j-3 k-2
//i是遍历保存,k是存值保存, j是栈顶保存
for(int i = n - 1; i >= 0; -- i){
if(nums[i] < k) return true;
while(!stk.empty() && stk.top() < nums[i]){
k = max(k, stk.top());
stk.pop();
}
stk.push(nums[i]);
}
return false;
}
};
1124. 表现良好的最长时间段
总结
从后往前,当前遍历值>= 栈顶 时弹栈 -> 栈单调递增(栈顶到栈底),可用来求当前元素右边的第一个比它大的元素。
- 从后往前,当前遍历值 <= 栈顶 时弹栈 -> 栈单调递减(栈顶到栈底),可用来求当前元素右边的第一个比它小的元素。
- 从前往后,当前遍历值>= 栈顶 时弹栈 -> 栈单调递增(栈顶到栈底),可用来求当前元素左边的第一个比它大的元素。
- 从前往后,当前遍历值 <= 栈顶 时弹栈 -> 栈单调递减(栈顶到栈底),可用来求当前元素左边的第一个比它小的元素。