84. 柱状图中最大的矩形

题目链接:

https://leetcode-cn.com/problems/largest-rectangle-in-histogram/

 

方法一:暴力法

柱子i和j范围内的最大矩形,我们可以遍历i至j去查找范围内最小的高度H,宽L为柱子i和j的距离。H*L就是柱子i和j范围内的最大矩形。

然后我们再遍历所有柱子的组合,最后在所有的情况中得到最大值。

1.	class Solution {  
2.	public:  
3.	    int largestRectangleArea(vector<int>& heights) {  
4.	        int n = heights.size();  
5.	        if (n == 0) {  
6.	            return 0;  
7.	        }  
8.	          
9.	        int max = 0;  
10.	        for (int i = 0; i < n; ++i) {  
11.	            int h = heights[i];  
12.	            for (int j = i; j < n; ++j) {  
13.	                h = h < heights[j] ? h : heights[j];  
14.	                int L = j - i + 1;  
15.	                if (h == 0) {  
16.	                    break;  
17.	                }  
18.	                max = max > h * L ? max : h * L;  
19.	            }  
20.	        }  
21.	        return max;  
22.	    }  
23.	};  

方法二:

我们可以分别求出包含每个柱子的最大矩形面积,然后选择最大的。

对于一个柱子求包含它的最大矩形,那么该柱子的高度必定等于矩形的高度。我们只要分别求出左右两边最近的高度小于当前柱子的下标,下标的距离即矩形的宽。当前柱子的高度即为矩形的高。

我们用leftMin[i]和rightMin[i]保存柱子i左右两边最近高度小于H的柱子下标。

特殊的,leftMin[0]=-1,rightMin[n-1] = n。

 

对于查找左边第一个小于柱子i的柱子下标,我们可以这样:

1.先判断是否大于左边相邻的柱子,是的话就将其下标记录至数组。

2.不是的话我们跳跃至leftMin[i-1],判断leftMin[i-1]的柱子是否小于柱子i。

如果柱子i-1高于柱子i,因为leftMin[i-1]+1至i-1均大于柱子i-1,所以该范围内的柱子也高于柱子i。

3.循环上述步骤直至找到符合条件的柱子。

1.	class Solution {  
2.	public:  
3.	    int largestRectangleArea(vector<int>& heights) {  
4.	        int n = heights.size();  
5.	        if (n == 0) {  
6.	            return 0;  
7.	        }  
8.	          
9.	        // 保存左边小于当前高度的柱子下标  
10.	        int leftMin[n] = {-1};  
11.	        for (int i = 1; i < n; ++i) {  
12.	            if (heights[i-1] < heights[i]) {  
13.	                leftMin[i] = i-1;  
14.	            } else {  
15.	                // 从小于上一个柱子的柱子开始往左查找。  
16.	                int j = leftMin[i-1];  
17.	                while (j >=0) {  
18.	                    if (heights[j] < heights[i]) {  
19.	                        break;  
20.	                    }  
21.	                    j = leftMin[j];  
22.	                }  
23.	                leftMin[i] = j;  
24.	            }  
25.	        }  
26.	          
27.	        int rightMin[n];  
28.	        rightMin[n - 1] = n;  
29.	          
30.	        for (int i = n - 2; i >= 0; --i) {  
31.	            if (heights[i+1] < heights[i]) {  
32.	                rightMin[i] = i+1;  
33.	            } else {  
34.	                // 从小于上一个柱子的柱子开始往右查找。  
35.	                int j = rightMin[i+1];  
36.	                while (j < n) {  
37.	                    if (heights[j] < heights[i]) {  
38.	                        break;  
39.	                    }  
40.	                    j = rightMin[j];  
41.	                }  
42.	                rightMin[i] = j;  
43.	            }  
44.	        }  
45.	          
46.	        int maxSize = 0;  
47.	        for (int i = 0; i < n; ++i) {  
48.	            int H = heights[i];  
49.	            int L = rightMin[i] - leftMin[i] - 1;  
50.	            maxSize = maxSize > H * L ? maxSize : H * L;  
51.	        }  
52.	        return maxSize;  
53.	    }  
54.	};  

方法三:单调栈

原理和方法二一样,求包含柱子i的最大矩形。

我们建立一个栈,依次遍历每个柱子。

如果栈空入栈下标-1。

如果当前柱子高度大于栈顶下标所表示柱子的高度,当前柱子下标入栈。

如果当前柱子小于栈顶下标表示柱子的高度,弹出栈顶元素并记录下其高度。当前柱子下标减去新的栈顶下标减一(矩形的宽),然后乘以刚刚出栈柱子的高度(矩形的高)。

1.	class Solution {  
2.	public:  
3.	    int largestRectangleArea(vector<int>& heights) {  
4.	        int n = heights.size();  
5.	        if (n == 0) {  
6.	            return 0;  
7.	        }  
8.	        stack<int> st;  
9.	        st.push(-1);  
10.	          
11.	        int maxSize = 0;  
12.	        for (int i = 0; i < n; ++i) {  
13.	            //cout << i << " st.top: " << st.top() << endl;  
14.	              
15.	            if (st.size() > 1 && heights[i] >= heights[st.top()]) {  
16.	                //cout << "push: " << i << endl;  
17.	                st.push(i);  
18.	            } else {  
19.	                while (st.size() > 1 && heights[i] < heights[st.top()]) {  
20.	                    //cout << "pop: " << st.top() << endl;  
21.	                    int H = heights[st.top()];  
22.	                    st.pop();  
23.	                    int L = i - st.top() - 1;  
24.	                    maxSize = maxSize > H * L ? maxSize : H * L;  
25.	                }  
26.	                //cout << "push: " << i << endl;  
27.	                st.push(i);      
28.	            }  
29.	        }  
30.	          
31.	        while (st.size() > 1) {  
32.	            int H = heights[st.top()];  
33.	            st.pop();  
34.	            int L = n - st.top() - 1;  
35.	            maxSize = maxSize > H * L ? maxSize : H * L;  
36.	        }  
37.	          
38.	        return maxSize;  
39.	    }  
40.	};  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值