单调栈、单调队列
单调栈、单调队列是在栈和队列的基础上加上单调结构的数据结构。如果一个元素入栈或入队,他会检查之前的元素,如果之前的元素不可能是答案的解,那么就弹出元素,使得当前元素入栈或入队。
例题
此题是单调队列,每次遇到一个元素,一直从队尾弹出,直到队尾元素大于该元素为止。还需要注意检查队头元素是否在区间内。
此题为单调栈,首先的思路是先计算每一个柱子能到达的左边的最远距离和右边的最远距离,然后在遍历一次数组即可。我们分两次计算,设置一个单调栈,从左向右遍历数组,如果碰见小于栈顶元素,那就弹出栈顶,当栈中的元素被某一个元素弹出的时候,就是最远距离。计算最右边界也是如此,处理边界的时候,我们可以设置哨兵节点,使最后的时候栈能保持空的状态。
长度为K的最小子序列,利用单调栈可以轻松实现,当栈顶元素能够被弹出的时候,需要满足一下条件:
- 剩余字符序列的长度能够满足所需要的K的长度
- 栈顶元素大于要插入的元素
int main()
{
string s;
int k;
cin >> s >> k;
stack<char> sta;
for (int i = 0; i < s.size(); i++)
{
while (!sta.empty() && sta.top() > s[i] && sta.size() - 1 + s.size() - i >= k)
{
sta.pop();
}
if (sta.size() < k)
sta.push(s[i]);
}
string ans;
while (!sta.empty())
{
ans.push_back(sta.top());
sta.pop();
}
reverse(ans.begin(), ans.end());
return ans;
return 0;
}
此题除了要求长度为K,还要求至少包含m个目标字符,也可以使用单调栈,只不过多加一个剩余字符序列的包含的目标字符能满足m个目标字符即可,以及何时才能加入字符。
class Solution
{
public:
string smallestSubsequence(string s, int k, char letter, int repetition)
{
vector<int> cnt(s.size() + 1);
for(int i = s.size() - 1; i >= 0; i--)
{
cnt[i] += cnt[i + 1] + (s[i] == letter);
}
stack<char> sta;
int req = 0;
for(int i = 0; i < s.size(); i++)
{
while(!sta.empty() && sta.top() > s[i] && int(sta.size() ) - 1 + int(s.size() ) - i >= k
&& req - (sta.top() == letter) + cnt[i] >= repetition)
{
if(sta.top() == letter) req--;
sta.pop();
}
if(sta.size() < k && repetition - (req + (s[i] == letter)) <= k - int(sta.size()) - 1)
{
sta.push(s[i]);
if(s[i] == letter) req++;
}
}
string ans;
while(!sta.empty())
{
ans.push_back(sta.top());
sta.pop();
}
reverse(ans.begin(),ans.end());
return ans;
}
};
// TODO LIST
- LC739. Daily Temperatures
- LC862. Shortest Subarray with Sum at Least K
- LC901. Online Stock Span
- LC907. Sum of Subarray Minimums