单调栈

单调栈

个人模板
84. 柱状图中最大的矩形 【困难】

【C++】【单调栈】84. 柱状图中最大的矩形 题解:单调栈 | 哨兵技巧(动画来自于编程狂想曲)

注意哨兵技巧,超级好用!

copy()函数算法标头的库函数,用于复制容器的元素,它将容器的元素从给定范围复制到给定起始位置的另一个容器。

Input:
//declaring & initializing an int array
int arr[] = { 10, 20, 30, 40, 50 };

//vector declaration
vector<int> v1(5);

//copying array elements to the vector
copy(arr, arr + 5, v1.begin());

Output:
//if we print the value
arr: 10 20 30 40 50
v1: 10 20 30 40 50

题解代码:

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        int area = 0;
        vector<int> newHeights(n+2,0);   // 加2个哨兵(小技巧,挺方便的)
        copy(heights.begin(), heights.end(), newHeights.begin() + 1);
        stack<int> s;
        for (int i = 0; i < newHeights.size(); ++i) {
            while (!s.empty() && newHeights[s.top()] > newHeights[i]) {
                int idx = s.top();
                s.pop();
                // 栈顶元素pop出后,新栈顶元素就是其左边界!!!!(自己没有考虑这个)
                int leftIdx = s.top();
                area = max(area, (i - leftIdx - 1) * newHeights[idx]);
            }
            s.emplace(i);
        }
        return area;
    }
};

经典单调栈的题目。

相关题目:

  • 316.去除重复字母(困难)
  • 901.股票价格跨度(中等)
  • 402.移掉K位数字
  1. 柱状图中最大的矩形 Hard
    剑指 Offer II 039. 直方图最大矩形面积 Hard

类似题:

  1. 子数组最小乘积的最大值 Medium
  2. 子数组的最小值之和 Medium
42. 接雨水
class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> s;
        int res = 0;
        for (int i = 0; i < height.size(); ++i) {
            while (!s.empty() && height[s.top()] < height[i]) {
                int curr = s.top();
                s.pop();
                if (s.empty()) break;
                int left = s.top();
                int right = i;
                int currHight = min(height[left], height[right]) - height[curr];
                res += (right - left - 1) * currHight;
            }
            s.psuh(i);
        }
        return res;
    }
};
739. 每日温度
class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        stack<int> s;
        int n = temperatures.size();
        vector<int> res(n);
        for (int i = 0; i < n; ++i) {
            while (!s.empty() && temperatures[s.top()] < temperatures[i]) {
                int curr = s.top();
                s.pop();
                res[curr] = i - curr;
            }
            s.push(i);
        }
        return res;
    }
};
496. 下一个更大元素 I
class Solution {	// 虽然简单但是花了很长时间,┭┮﹏┭┮
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size();
        vector<int> res(m);
        unordered_map<int,int> numIdx;  // 记录nums2的值和 下一个更大元素II
        stack<int> s;
        for (int i = 0; i < nums2.size(); ++i) {
            numIdx[nums2[i]] = -1; // 设置默认值
            while (!s.empty() && s.top() < nums2[i]) {
                int curr = s.top();
                s.pop();
                numIdx[curr] = nums2[i];
            }
            s.push(nums2[i]);
        }
        for (int i = 0; i < m; ++i) {
            res[i] = numIdx[nums1[i]];
        }
        return res;
    }
};
901. 股票价格跨度
class StockSpanner {
public: // 直接把之前小于的数据删除是我没想到的(可以减少数据量)
    stack<pair<int,int>> s;
    StockSpanner() {
    }
    
    int next(int price) {
        pair<int,int> curr(price,1);
        while(!s.empty() && s.top().first <= price) {
            curr.second += s.top().second;
            s.pop();
        }
        s.push(curr);
        return curr.second;
    }
};
402. 移掉 K 位数字
// 个人代码,效率贼低
class Solution {
public:
    string removeKdigits(string num, int k) {
        // 如果后面的数字小于前面的数字则删除前面的数字,使用单调栈
        if (k == num.size()) return "0";
        stack<int> s;
        string res;
        for (auto elem : num) {
            while (!s.empty() && s.top() > elem && k) {
                s.pop();
                k--;
            }
            s.push(elem);
        }
        // 没有去除任何一个元素
        while (k--)  s.pop();
        // 将s倒出来并反转
        while (!s.empty()) {
            res += s.top();
            s.pop();
        }
        reverse(res.begin(), res.end());
        res.erase(0, res.find_first_not_of("0"));   // 去除前置0
        return (res == "")?"0":res;
    }
};
1081. 不同字符的最小子序列
class Solution {
public:
    string smallestSubsequence(string s) {
        unordered_map<char,int> numCnt;
        int n = s.size();
        for (auto elem : s) {
            numCnt[elem] += 1;
        }
        stack<char> stk;
        unordered_set<char> exist;  //保证该元素是否存在stack中,这个思路很妙(可惜自己没考虑好)
        for (auto elem : s) {
            if (exist.find(elem) == exist.end()) {  // 元素不存在
                while (!stk.empty() && stk.top() > elem && numCnt[stk.top()] > 0) {
                    int curr = stk.top();
                    exist.erase(curr);
                    stk.pop();
                }
                stk.push(elem);
                exist.insert(elem);
            }
            numCnt[elem]--;
        }
        string res;
        while (!stk.empty()) {
            res += stk.top();    
            stk.pop();
        }
        reverse(res.begin(),res.end());
        return res;
    }
};

注:316. 去除重复字母与1081题目一致。

402. 移掉 K 位数字
class Solution {
public:
    string removeKdigits(string num, int k) {
        // 如果后面的数字小于前面的数字则删除前面的数字,使用单调栈
        if (k == num.size()) return "0";
        stack<int> s;
        string res;
        for (auto elem : num) {
            while (!s.empty() && s.top() > elem && k) {
                s.pop();
                k--;
            }
            s.push(elem);
        }
        // 没有去除任何一个元素
        while (k--)  s.pop();
        // 将s倒出来并反转
        while (!s.empty()) {
            res += s.top();
            s.pop();
        }
        reverse(res.begin(), res.end());
        res.erase(0, res.find_first_not_of("0"));   // 去除前置0
        return (res == "")?"0":res;
    }
};
321. 拼接最大数 (未完成)
1673. 找出最具竞争力的子序列 (未完成)
84. 柱状图中最大的矩形 (未完成)
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        int area = 0;
        vector<int> newHeights(n+2,0);   // 加2个哨兵(小技巧,挺方便的)
        copy(heights.begin(), heights.end(), newHeights.begin() + 1);
        stack<int> s;
        for (int i = 0; i < newHeights.size(); ++i) {
            while (!s.empty() && newHeights[s.top()] > newHeights[i]) {
                int idx = s.top();
                s.pop();
                // 栈顶元素pop出后,新栈顶元素就是其左边界!!!!(自己没有考虑这个)
                int leftIdx = s.top();
                area = max(area, (i - leftIdx - 1) * newHeights[idx]);
            }
            s.emplace(i);
        }
        return area;
    }
};
1856. 子数组最小乘积的最大值 (未完成)
1857. 有向图中最大颜色值 (未完成)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值