单调栈除了经典的用法外,还可以用来维持求解答案的可能性
1) 单调栈里的所有对象按照规定好的单调性来组织
2) 当某个对象进入单调栈时,会从栈顶开始弹出对后续求解答案没有帮助的对象
3) 每个对象弹出时,结算当前对象对应的答案
不管怎么利用单调栈,都是先分析题目发现单调性,用单调栈解决问题
class Solution {
public:
int maxWidthRamp(vector<int>& nums) {
int n = nums.size();
vector<int> stack(n, 0);
int ans = 0;
int top = 0;
stack[top++] = 0;
for (int i = 1; i < n; i++) {
if (nums[i] < nums[stack[top - 1]])
stack[top++] = i;
}
for (int i = n - 1; i >= 0; i--) {
while (top > 0 && nums[i] >= nums[stack[top - 1]]) {
ans = max(ans, i - stack[--top]);
}
}
return ans;
}
};
如果A小于B并且A在B的左边,那么B不可能是答案的左边界,因为能和B产生元组的,一定可以和A产生元组,而且距离会更大。所以先遍历一遍数组用单调栈以小压大的方式收集元素,然后从后遍历元素,收集完答案就可以弹出栈了,再往前遍历不会产生还大的答案了
class Solution {
public:
int rem[26];
bool ok[26] = {false};
string removeDuplicateLetters(string s) {
for (int i = 0; i < s.size(); i++)
rem[s[i] - 'a']++;
char stack[10001] = {'0'};
int l = 0, r = 0;
for (char a : s) {
if (!ok[a - 'a']) {
while (r > 0 && stack[r - 1] > a &&
rem[stack[r - 1] - 'a'] > 0) {
ok[stack[r - 1] - 'a'] = false;
r--;
}
stack[r++] = a;
ok[a - 'a'] = true;
}
rem[a - 'a']--;
}
string ans;
while (l < r) {
ans += stack[l++];
}
return ans;
}
};
当遍历到一个字符时,如果这个字符已经记录过,就跳过;如果没有遍历过,此时如果栈的顶部
的字符字典序大于遍历到的字符并且栈顶的元素后面会出现,就可以把栈顶的字符弹出,然后压入
这个字符。最后收集栈里的字符集成答案
class Solution {
public:
int totalSteps(vector<int>& nums) {
int stack[100001][2];
int ans = 0;
int top = 0;
for (int i = nums.size() - 1; i >= 0; i--) {
int rem = 0;
while (top > 0 && nums[i] > nums[stack[top - 1][0]]) {
rem = max(rem + 1, stack[--top][1]);
}
stack[top][0] = i;
stack[top++][1] = rem;
ans = max(ans, rem);
}
return ans;
}
};
具体解析看使数组按非递减顺序排列
class Solution {
public:
int height[151];
int stack[151];
int f(int m) {
int top = 0;
int ans = 0;
for (int i = 0; i < m; i++) {
while (top > 0 && height[stack[top - 1]] >= height[i]) {
int cur = stack[--top];
if (height[cur] > height[i]) {
int left = top == 0 ? -1 : stack[top - 1];
int len = i - left - 1;
int bottom = max(height[i], left == -1 ? 0 : height[left]);
ans += (height[cur] - bottom) * (len + 1) * len / 2;
}
}
stack[top++] = i;
}
while (top > 0) {
int cur = stack[--top];
int left = top == 0 ? -1 : stack[top - 1];
int len = m - left - 1;
int bottom = left == -1 ? 0 : height[left];
ans += (height[cur] - bottom) * (len + 1) * len / 2;
}
return ans;
}
int numSubmat(vector<vector<int>>& mat) {
int n = mat.size();
int m = mat[0].size();
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
height[j] = mat[i][j] == 0 ? 0 : height[j] + 1;
}
ans += f(m);
}
return ans;
}
};
具体看解析统计全为1的子矩阵