算法学习——单调栈

84. 柱状图中最大的矩形

题目

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例 1:
算法学习——单调栈_第1张图片

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

示例 2:
算法学习——单调栈_第2张图片

输入: heights = [2,4]
输出: 4

提示:

1 <= heights.length <=105
0 <= heights[i] <= 104

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

class Solution {
public:
    int largestRectangleArea0(vector& heights) {
        if (heights.empty()) {
            return 0;
        }
        heights.push_back(0);
        vector index;
        int res = 0;
        for (int i = 0; i < heights.size(); ++i) {
            while (index.size() > 0 && heights[index.back()] >= heights[i]) {
                int h = heights[index.back()];
                index.pop_back();
                int sidx = index.size() > 0 ? index.back() : -1;
                res = max(res, h * (i - sidx - 1));
            }
            index.push_back(i);
        }
        return res;
    }

    int largestRectangleArea1(vector& heights)
    {
        if (heights.empty()) {
            return 0;
        }
        heights.push_back(0);   // 保证单调栈中元素全被弹出
        stack st;
        int res = 0;
        for (int i = 0; i < heights.size(); ++i) {
            while (st.size() > 0 && heights[st.top()] >= heights[i]) {
                int height = heights[st.top()];
                st.pop();
                int sid = !st.empty() ? st.top() : -1;
                int width = i - sid - 1;
                res = max(res, height * width);
            }
            st.push(i);
        }
        return res;
    }

    int largestRectangleArea(vector& heights)
    {
        if (heights.empty()) {
            return 0;
        }
        heights.insert(heights.begin(), 0);
        heights.push_back(0);

        stack st;
        st.push(0);

        int res = 0;
        for (int i = 1; i < heights.size(); ++i) {
            while (heights[i] < heights[st.top()]) {
                int h = heights[st.top()];
                st.pop();
                int w = i - st.top() - 1;
                res = max(res, h * w);
            }
            st.push(i);
        }
        return res;
    }
};

85. 最大矩形

题目

难度困难1055收藏分享切换为英文接收动态反馈

给定一个仅包含 01 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

示例 1:

算法学习——单调栈_第3张图片

输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:6
解释:最大矩形如上图所示。

示例 2:

输入:matrix = []
输出:0

示例 3:

输入:matrix = [["0"]]
输出:0

示例 4:

输入:matrix = [["1"]]
输出:1

示例 5:

输入:matrix = [["0","0"]]
输出:0

题解

class Solution {
public:
    int largestRectangleArea(vector& heights)
    {
        if (heights.empty()) {
            return 0;
        }
        // heights.insert(heights.begin(), 0);
        // heights.push_back(0);

        stack st;
        st.push(0);

        int res = 0;
        for (int i = 1; i < heights.size(); ++i) {
            while (heights[i] < heights[st.top()]) {
                int h = heights[st.top()];
                st.pop();
                int w = i - st.top() - 1;
                res = max(res, h * w);
            }
            st.push(i);
        }
        return res;
    }

    int maximalRectangle(vector>& matrix) {
        if (matrix.empty()) {
            return 0;
        }
        vector heights(matrix[0].size() + 2, 0);
        int res = 0;
        for (int i = 0; i < matrix.size(); ++i) {
            for (int j = 0; j < matrix[0].size(); ++j) {
                if (matrix[i][j] == '1') {
                    heights[j+1] += 1;
                } else {
                    heights[j+1] = 0;
                }
            }
            res = max(res, largestRectangleArea(heights));
        }
        return res;
    }
};

739. 每日温度

题目

难度中等892收藏分享切换为英文接收动态反馈

请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例 1:

输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]

示例 2:

输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]

示例 3:

输入: temperatures = [30,60,90]
输出: [1,1,0]

提示:

  • 1 <= temperatures.length <= 105
  • 30 <= temperatures[i] <= 100

题解

class Solution {
public:
    vector dailyTemperatures(vector& temperatures) {
        if (temperatures.empty()) {
            return {};
        }

        stack st;
        st.push(0);
        vector res(temperatures.size(), 0);

        for (int i = 1; i < temperatures.size(); ++i) {
            
            while (!st.empty() && temperatures[i] > temperatures[st.top()]) {
                int t = st.top();
                st.pop();
                res[t] = i - t;
            }
            st.push(i);
        }

        return res;
    }
};

503. 下一个更大元素 II

题目

难度中等497收藏分享切换为英文接收动态反馈

给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

示例 1:

输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数; 
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

注意: 输入数组的长度不会超过 10000。

题解

class Solution {
public:
    vector nextGreaterElements0(vector& nums) {
        if (nums.empty()) {
            return {};
        }
        int n = nums.size();
        vector res(2 * n, -1);
        nums.insert(nums.end(), nums.begin(), nums.end());
        stack st;
        st.push(0);
        for (int i = 1; i < nums.size(); ++i) {
            while (!st.empty() && nums[i] > nums[st.top()]) {
                res[st.top()] = nums[i];
                st.pop();
            }
            st.push(i);
        }
        vector ret(res.begin(), res.begin() + n);
        return ret;
    }

    vector nextGreaterElements(vector& nums) {
        int n = nums.size();
        vector ret(n, -1);
        stack stk;
        for (int i = 0; i < n * 2 - 1; i++) {
            while (!stk.empty() && nums[stk.top()] < nums[i % n]) {
                ret[stk.top()] = nums[i % n];
                stk.pop();
            }
            stk.push(i % n);
        }
        return ret;
    }
};

42. 接雨水

题目

难度困难2753收藏分享切换为英文接收动态反馈

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

算法学习——单调栈_第4张图片

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

题解

class Solution {
public:

    int trap(vector& height) {
        // 单调栈
        stack st;
        st.push(0);
        int sum = 0;
        for(int i = 1; iheight[st.top()]){
                int mid = st.top();
                st.pop();
                if(!st.empty()){
                    int h = min(height[st.top()], height[i])-height[mid];
                    int w = i - st.top() -1;
                    sum += h*w;
                }
            }
            st.push(i);
        }
        return sum;
    }


    int trap1(vector& height) {
        // 动态规划
        if(height.size() <= 2) return 0;
        vector leftMax(height.size(), 0);
        vector rightMax(height.size(), 0);
        leftMax[0] = height[0];
        for(int i=1; i=0; i--){
            rightMax[i] = max(height[i], rightMax[i+1]);
        }

        int sum = 0;
        for(int i=0; i 0) sum += tmp;
        }

        return sum;

    }


    
    int trap0(vector& height) {
        // 自解答
        if (height.size() == 0) {
            return 0;
        }

        // 从左侧的最大值
        vector leftMax(height.size(), 0);
        // 从右侧的最大值
        vector rightMax(height.size(), 0);

        int tmp = height[0];
        for(int i=1; itmp) {
                leftMax[i] = height[i];
                tmp = height[i];
            } else {
                leftMax[i] = tmp;
            }
        }
        tmp = height[height.size() - 1];
        for(int i = height.size() - 2; i >= 0; --i) {
            if(height[i]>tmp) {
                rightMax[i] = height[i];
                tmp = height[i];
            } else {
                rightMax[i] = tmp;
            }
        }

        int res = 0;

        for(int i=0; i

901. 股票价格跨度

题目

难度中等139收藏分享切换为英文接收动态反馈

编写一个 StockSpanner 类,它收集某些股票的每日报价,并返回该股票当日价格的跨度。

今天股票价格的跨度被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。

例如,如果未来7天股票的价格是 [100, 80, 60, 70, 60, 75, 85],那么股票跨度将是 [1, 1, 1, 2, 1, 4, 6]

示例:

输入:["StockSpanner","next","next","next","next","next","next","next"], [[],[100],[80],[60],[70],[60],[75],[85]]
输出:[null,1,1,1,2,1,4,6]
解释:
首先,初始化 S = StockSpanner(),然后:
S.next(100) 被调用并返回 1,
S.next(80) 被调用并返回 1,
S.next(60) 被调用并返回 1,
S.next(70) 被调用并返回 2,
S.next(60) 被调用并返回 1,
S.next(75) 被调用并返回 4,
S.next(85) 被调用并返回 6。

注意 (例如) S.next(75) 返回 4,因为截至今天的最后 4 个价格
(包括今天的价格 75) 小于或等于今天的价格。

提示:

  1. 调用 StockSpanner.next(int price) 时,将有 1 <= price <= 10^5
  2. 每个测试用例最多可以调用 10000StockSpanner.next
  3. 在所有测试用例中,最多调用 150000StockSpanner.next
  4. 此问题的总时间限制减少了 50%。

题解

class StockSpanner {
public:
    StockSpanner() {
        
    }

    int next(int price) {
        int w = 1;
        while (!prices.empty() && prices.top() <= price) {
            prices.pop();
            w += weights.top();
            weights.pop();
        }

        prices.push(price);
        weights.push(w);
        return w;
    }

private:
    stack prices, weights;
};

239. 滑动窗口最大值

题目

难度困难1213收藏分享切换为英文接收动态反馈

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

示例 2:

输入:nums = [1], k = 1
输出:[1]

示例 3:

输入:nums = [1,-1], k = 1
输出:[1,-1]

示例 4:

输入:nums = [9,11], k = 2
输出:[11]

示例 5:

输入:nums = [4,-2], k = 2
输出:[4]

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

题解

class Solution {
public:
    vector maxSlidingWindow(vector& nums, int k) {
        int n = nums.size();
        deque q;
        for (int i = 0; i < k; i++) {
            while (!q.empty() && nums[i] >= nums[q.back()]) {
                q.pop_back();
            }
            q.push_back(i);
        }

        vector ans = {nums[q.front()]};
        for (int i = k; i < n; i++) {
            while (!q.empty() && nums[i] >= nums[q.back()]) {
                q.pop_back();
            }
            q.push_back(i);
            while (q.front() <= i - k) {
                q.pop_front();
            }
            ans.push_back(nums[q.front()]);
        }
        return ans;
    }
};

962. 最大宽度坡

题目

难度中等133收藏分享切换为英文接收动态反馈

给定一个整数数组 A是元组 (i, j),其中 i < jA[i] <= A[j]。这样的坡的宽度为 j - i

找出 A 中的坡的最大宽度,如果不存在,返回 0 。

示例 1:

输入:[6,0,8,2,1,5]
输出:4
解释:
最大宽度的坡为 (i, j) = (1, 5): A[1] = 0 且 A[5] = 5.

示例 2:

输入:[9,8,1,0,1,9,4,0,4,1]
输出:7
解释:
最大宽度的坡为 (i, j) = (2, 9): A[2] = 1 且 A[9] = 1.

提示:

  1. 2 <= A.length <= 50000
  2. 0 <= A[i] <= 50000

题解

class Solution {
public:
    // 暴力,超时
    int maxWidthRamp0(vector& nums) {
        int maxLen = 0;
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (nums[j] >= nums[i]) {
                    maxLen = max(maxLen, j - i);
                }
            }
        }
        return maxLen;
    }

    int maxWidthRamp(vector& nums) {
        int n = nums.size();
        stack stk;
        stk.push(0);
        // 单调递减队列
        for (int i = 1; i < n; ++i) {
            if (nums[i] < nums[stk.top()]) {
                stk.push(i);
            }
        }
        int maxLen = 0;
        for (int i = n - 1; i >= 0; i--) {
            while (!stk.empty() && nums[i] >= nums[stk.top()]) {
                maxLen = max(maxLen, i - stk.top());
                stk.pop();
            }
        }
        return maxLen;
    }
};

402. 移掉 K 位数字

题目

难度中等657收藏分享切换为英文接收动态反馈

给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。

示例 1 :

输入:num = "1432219", k = 3
输出:"1219"
解释:移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219 。

示例 2 :

输入:num = "10200", k = 1
输出:"200"
解释:移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。

示例 3 :

输入:num = "10", k = 2
输出:"0"
解释:从原数字移除所有的数字,剩余为空就是 0 。

提示:

  • 1 <= k <= num.length <= 105
  • num 仅由若干位数字(0 - 9)组成
  • 除了 0 本身之外,num 不含任何前导零

题解

class Solution {
public:
    string removeKdigits(string num, int k) {
        int n = num.size();
        vector stk;
        for (auto &c : num) {
            while (!stk.empty() &&  stk.back() > c  && k != 0) {
                stk.pop_back();
                k--;
            }
            stk.push_back(c);
        }

        for (; k > 0; k--) {
            stk.pop_back();
        }

        string res = "";
        bool f = true;
        for (auto &c : stk) {
            if (f && c == '0') {
                continue;
            }
            f = false;
            res += c;
        }
        return res == "" ? "0" : res;
    }
};

你可能感兴趣的:(算法,算法,c++)