单调栈入门学习 + 题型

概念导入:

        在数组array中,定义F(x)操作: 以O(1)的时间复杂度查找元素 x 左边第一个比它小的元素 l 以及右边第一个比它小的元素 r ,可以通过中心扩展的方式找到,时间复杂度也不会太高,但如果要求数组中所有元素进行F(x)操作呢,又该如何降低复杂度到O(n)呢?

算法定义:

        单调栈:通过维护栈内的单调性形成的特殊的栈。

算法特性及作用:

        在遍历array的每一个元素时:

        第一步,如果遇到第一个比栈顶元素小的值 x ,就开始出栈,直到当前的栈顶元素的值比 x 小,或者栈为空。

        第二步:将 x 入栈

        可见栈顶元素比 x 大,同时也比栈内的每一个元素大。栈顶上一个元素 l,一定是左边比x 小并且离 x 最近的第一个元素, 如果l 与 x 中间还存在比 l 小的元素,l一定会在 x 入栈前出栈。 

        作用:用于计算最大柱形面积,查找驼峰使用。

简单题型:每日温度

        题目描述:给定一个数组array, 要求返回一个数组answer ,其中 answer[i] 是指下一个比 array[i] 大的元素的索引,如果后面没有比它大的,answer[i] = 0。

        个人思路:基本单调栈写法,保持栈内单调递减。

代码实现:

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        int n = temperatures.size(),cnt = 0;
        vector<int> ans(n,0); // 先初始化全为零
        vector<pair<int,int> > st; // pair.first 存储温度值,pair.second() 存储索引值。
        for (auto p : temperatures) {
            while (st.size() && st.back().first < p) {
                auto k = st.back().second;
                ans[k] = cnt - k;  // 索引间的距离
                st.pop_back();
            }
            st.push_back({p,cnt});
            cnt++; // 当前位置的索引
        }
        return ans;
    }
};

简单题型:移除 k 位整数

        题目描述:给定数字字符串,去除其中的 k 位,以字符串的形式返回剩余位数的最小值。

        个人思路:字符串中越高位的权值越大,要让剩余数越小,越高位上的数就要尽可能的小。但不管删去哪一位,最终数字的位数还是一样大的,故重点是要保证高位上的数字小即可。列如14781  -> 中 4 比左边的数大,如果删除4 得到1721,同理 7 比左边的数要大,删除7得到1481,发现删除7更合理。8比左边的数要大,删除得到1471,1 比左边的数要小,删除得1478。

发现删除单调递增序列中最大的数带来的效果最好。

        不难发现就是遍历过程中比较左侧的数是否比当前数大,大的话就删除该数字,因为删除是一个动态的过程,每删除一个就要重新遍历,所以当采用朴素的算法就是O(n ^ 2)。

        因为是找前面最近的一个比当前数小的值,可以用 单调栈 加速这一过程,维护一个单调递增的栈,遍历字符串的每一个数字时:

        第一步:如果当前数字比栈顶元素小就持续删除栈顶,直到栈为空或者k (剩余所需删除数)为0。

        第二步:将当前数字入栈

        特殊处理1:遍历完后,如果k(剩余删除数)还未用完,从末尾继续删除。

        特殊处理2:去除前导0,并且字符串若全是0,如"00000",最终返回0.

代码实现:

class Solution {
public:
    string removeKdigits(string num, int k) {
        vector<char> st;
        for (int i = 0; i < num.size(); i++) {
            while (st.size() && k && st.back() > num[i]) { // 第一步
                st.pop_back(); 
                k--;
            }
            st.push_back(num[i]); // 第二步
        }
        for (int i = 0; i < k; i++) { // 如果遍历完字符串,还需要删除数字,就从末尾开始删除 
            st.pop_back();
        }
        string ans = "";
        // 去除前导0
        bool lead = false;
        for (auto c : st) {
            if (!lead && c == '0') continue;
            else {
                lead = true;
                ans += c;
            }
        }
        // 特判: ans为空时,返回0.
        return ans.size() ? ans : "0";
    }
};

个人总结:

        单调栈只是数据结构的一种,单纯的单调栈并不能解决问题,它的作用在于加速查找该元素左右两边比它大的元素的位置,做题时,应该先想清楚朴素算法在构思能否用单调栈进行加速。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值