单调栈
对无重复元素的数组\([3,2,1,7,0,4,5,6]\),求左侧和右侧第一个比nums[i]
大(小)的元素索引:
对于greater,左侧的答案为\([-1,0,1,-1,3,3,3,3]\),右侧的答案为\([3,3,3,-1,5,6,7,-1]\);
对于smaller,左侧的答案为\([-1,-1,-1,2,-1,4,5,6]\),右侧的答案为\([1,2,4,4,-1,-1,-1,-1]\)。 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// 数组中无重复值 first存左侧索引 second存右侧索引
vector<pair<int, int>> monotonousStack(vector<int>& nums) {
stack<int> s; // store index
vector<pair<int, int>> ans(nums.size()); // return index
for (int i = 0; i < nums.size(); ++i) {
// 求smaller. 若需greater, 改为 nums[i] > nums[s.top()]
while (!s.empty() && nums[i] < nums[s.top()]) {
int idx = s.top(); s.pop();
ans[idx].first = s.empty() ? -1 : s.top();
ans[idx].second = i;
}
s.push(i);
}
while (!s.empty()) {
int idx = s.top(); s.pop();
ans[idx].first = s.empty() ? -1 : s.top();
ans[idx].second = -1;
}
return ans;
}
如果数组中存在重复元素,比如\([3,2,3,4,4,3,1]\):
对于greater,左侧的答案为\([-1,0,-1,-1,-1,4,5]\),右侧的答案为\([3,2,3,-1,-1,-1,-1]\);
对于smaller,左侧的答案为\([-1,-1,1,2,2,1,-1]\),右侧的答案为\([1,6,6,5,5,6,-1]\)
对于有重复元素,如果直接使用上述无重元素的代码,有以下情况:
nums[i] < nums[s.top()]
:左侧变为\([-1,-1,1,2,3,2,-1]\),即左侧第一个小于等于nums[i]
的元素位置,不再是严格小于;右侧不变,仍然严格小于nums[i] <= nums[s.top()]
:左侧不变,仍然严格小于;右侧变为\([1,6,5,4,5,6,-1]\),即右侧第一个小于等于nums[i]
的元素位置,不再是严格小于nums[i] > nums[s.top()]
:左侧变为\([-1,0,0,-1,3,4,5]\),即左侧第一个大于等于nums[i]
的元素位置,不再是严格大于;右侧不变,仍然严格大于nums[i] >= nums[s.top()]
:左侧不变,仍然严格大于;右侧变为\([2,2,3,4,-1,-1,-1]\),即右侧第一个大于等于nums[i]
的元素位置,不再是严格大于
1 | // 左边和右边第一个比nums[i]小(大)的元素索引 栈自底向上从小到大(从大到小) |
单调队列
单调队列主要用来解决: 数组中所有长度为\(k\)的区间最值问题.
实现
1 | // 求所有区间长度为k的最大值 |