单调栈即需要保证入栈的元素是保持递增或者递减的。如果有违反递增或者递减的原则,那么就需要通过弹出栈的方式来保持单调栈的性质。
单调栈常被用来解决滑动窗口中元素最大值和最小值的问题。
给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
观察窗口的滑动过程:
当窗口区间为
[
i
,
j
]
\left [ i, j \right ]
[i,j] ,对应的窗口中的值的集合为
{
n
u
m
i
,
n
u
m
i
+
1
,
.
.
.
n
u
m
j
}
\left \{ num_i,num_{i+1},... num_j \right \}
{numi,numi+1,...numj}, 当窗口从左向右移动一格,那么会舍弃掉
n
u
m
i
num_{i}
numi,滑动窗口内增加一个值
n
u
m
j
+
1
num_{j+1}
numj+1,如果集合
{
n
u
m
i
,
n
u
m
i
+
1
,
.
.
.
n
u
m
j
}
\left \{ num_i,num_{i+1},... num_j \right \}
{numi,numi+1,...numj}中只要有值比
n
u
m
j
+
1
num_{j+1}
numj+1小,那么只要往右边滑动,最大值肯定不是集合中比
n
u
m
j
+
1
num_{j+1}
numj+1小的值,因此可以将该集合中比
n
u
m
j
+
1
num_{j+1}
numj+1小的值舍弃,照此思路,构建单调递减栈。
class Solution {
public:
class MonotonicStack{
deque<long long > deq;
int max = INT_MIN;
vector<int> vec;
public:
MonotonicStack(vector<int> num, int k){
vec = num;
for(int i = 0; i < k && i < num.size();++i)
{
if(num[i] > max){
max = num[i];
deq.clear();
deq.push_back(num[i]);
}else{
while(deq[deq.size() -1] < num[i]) {
deq.pop_back();
}
deq.push_back(num[i]);
}
}
}
public :
void push(int i) {
if(vec[i] > max){
max = vec[i];
deq.clear();
deq.push_back(vec[i]);
} else {
while(deq.size() > 0 && deq[deq.size() -1] < vec[i]) {
deq.pop_back();
}
deq.push_back(vec[i]);
}
}
void pop(int start) {
if(deq.size() > 0 && vec[start] == max) {
max = deq.size() > 1 ? deq[1] : INT_MIN;
deq.pop_front();
}
}
int getMaxNum(){
return this->max;
}
};
public :
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(k <= 0){
return vector<int> {};
}
vector<int> vec;
MonotonicStack* monotonicStack = new MonotonicStack(nums, k);
if(k >= nums.size()){
vec.push_back(monotonicStack->getMaxNum());
} else {
for(int i = k; i < nums.size(); ++i) {
vec.push_back(monotonicStack -> getMaxNum());
monotonicStack -> pop(i-k);
monotonicStack ->push(i);
}
vec.push_back(monotonicStack -> getMaxNum());
}
delete monotonicStack;
monotonicStack = nullptr;
return vec;
}
};
构造一个内部类,该类使用双向队列deque保存滑动窗口单调栈的值,在MonotonicStack的构造函数中初始化单调递减栈,然后通过循环调用MonotonicStack的pop和push函数,更新滑动窗口的 m a x max max值。