单 调 栈——进阶

 单调栈除了经典的用法外,还可以用来维持求解答案的可能性

 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;
    }
};

具体解析看使数组按非递减顺序排列

统计全为1的子矩阵

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的子矩阵 

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值