【C++】单调栈解法的相关题目

一、解题背景

  在刷题的过程中遇到部分比较难的题目是需要利用单调栈的思想来进行求解题目的,这类问题往往有一个统一的思路,需要在遍历的过程中保存一个单调递增的序列或者是单调递减的序列,一旦不满足单调性的时候,就就需要做一些处理来获取我们想要的结果。

二、部分题目

leet84. 柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        if (n==0) return 0;
        int area=0;
        // 关键是需要“哨兵”,防止存在一直递增的情况无法结束计算最大矩形
        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        stack<int> st;
        st.push(0);
        for (int i=1; i<heights.size(); i++) {
            while (!st.empty() && heights[i]<heights[st.top()]) {
                int h = heights[st.top()];
                st.pop();
                area = max(area, (i-st.top()-1)*h);
            }
            st.push(i);
        }
        return area;
    }
};

leet85. 最大矩形

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

输入:matrix = [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”,“0”,“0”,“1”,“0”]]
输出:6
解释:最大矩形如下图所示。
在这里插入图片描述

class Solution {
public:
	// 将这个矩形的从第一层开始,看成多个高度的柱状图,这里可以看做为
	/*
	每一层看作是柱状图,可以套用84题柱状图的最大面积。
	
	第一层柱状图的高度["1","0","1","0","0"],最大面积为1;
	
	第二层柱状图的高度["2","0","2","1","1"],最大面积为3;
	
	第三层柱状图的高度["3","1","3","2","2"],最大面积为6;
	
	第四层柱状图的高度["4","0","0","3","0"],最大面积为4;
	*/
    int maximalRectangle(vector<vector<char>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();
        if (m==0||n==0) return 0;
        int ans=0;
        vector<int> height(n, 0);

        for (int i=0; i<m; i++) {
            for (int j=0; j<n; j++) {
                if (matrix[i][j]=='1')
                    height[j]++;
                else 
                    height[j]=0;
            }
            ans = max(ans, largestRecArea(height));
        }
        return ans;
    }
    int largestRecArea(vector<int> height) {
        height.insert(height.begin(), 0);
        height.push_back(0);
        stack<int> st;
        st.push(0);
        int area=0;
        for (int i=1; i<height.size(); i++) {
            while (!st.empty() && height[st.top()]>height[i]) {
                int h= height[st.top()];
                st.pop();
                area = max(area, (i-st.top()-1)*h);
            }
            st.push(i);
        }
        return area;
    }
};

leet42. 接雨水

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

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        if (n==0) return 0;
		// 方法一
        // int area=0;
        // stack<int> st;
  
        // for (int i=0; i<n; i++) {
        //     while (!st.empty() && height[i]>height[st.top()]) {
        //         int low = st.top();
        //         st.pop();
        //         while (!st.empty() && height[st.top()]==height[low]) {
        //             st.pop();
        //         }
        //         if (!st.empty()) {
        //             int l = st.top();
        //             area += (min(height[l], height[i])-height[low])*(i-l-1);
        //         }
                
        //     }
        //     st.push(i);
        // }
        // return area;
        
        // 方法二
        // 找出对应每个位置左边最大和右边最大的柱子
        vector<int> left(n,0);
        vector<int> right(n,0);
        for (int i=1; i<n; i++) {
            left[i] = max(left[i-1], height[i-1]);
        }
            
        
        for (int j=n-2; j>=0; j--) {
            right[j] = max(right[j+1], height[j+1]);
        }
        int area=0;
        for (int i=1; i<n-1; i++) {
            int level = min(left[i], right[i]);
            area += max(0, level-height[i]);
        }
        return area;
    }
};

leet739. 每日温度

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指在第 i 天之后,才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例子:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        int n = temperatures.size();
        if (n==0) return {};
        // unordered_map<int,int> mp;
        stack<int> st;
        vector<int> res(n, 0);
        for (int i=0; i<n; i++) {
            while (!st.empty() && temperatures[st.top()]<temperatures[i]) {
                res[st.top()]=i-st.top();
                st.pop();
            }
            st.push(i);
        }
        
        return res;
    }
};

leet496. 下一个更大元素 I
输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:

  • 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
  • 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
  • 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int, int> mp;
        vector<int> res;
        if (nums1.size()==0) return res;
        // 方法一
        // for (int i=0; i<nums2.size(); i++) {
        //     mp[nums2[i]] = i;
        // }
        // for (auto n:nums1) {
        //     int idx = mp[n];
        //     int flag = false;
        //     for (int j=idx+1; j<nums2.size(); j++) {
        //         flag = false;
        //         if (nums2[j]>n) {
        //             res.push_back(nums2[j]);
        //             flag = true;
        //             break;
        //         }
        //         else continue;
        //     }
        //     if (!flag) res.push_back(-1);
        // }
        // return res;

		// 方法二
        res.resize(nums1.size());
        stack<int> st;
        for (auto n: nums2) {
            while (!st.empty() && st.top()<n) {
                mp[st.top()]= n;
                st.pop();
            }
            st.push(n);
        }
        for (int i=0; i<nums1.size(); i++) {
            res[i] = mp.find(nums1[i])!=mp.end() ? mp[nums1[i]] : -1;
        }
        return res;
        
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郝同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值