LeetCode(84): 柱狀圖中最大的矩形


Hard!

題目描述:

給定 n 個非負整數,用來表示柱狀圖中各個柱子的高度。每個柱子彼此相鄰,且寬度為 1 。

求在該柱狀圖中,能夠勾勒出來的矩形的最大面積。

以上是柱狀圖的示例,其中每個柱子的寬度為 1,給定的高度為 [2,1,5,6,2,3]

圖中陰影部分為所能勾勒出的最大矩形面積,其面積為 10 個單位。

示例:

輸入: [2,1,5,6,2,3]
輸出: 10

解題思路:

這道題讓求直方圖中最大的矩形,http://fisherlei.blogspot.com/2012/12/leetcode-largest-rectangle-in-histogram.html這里有一種很好的優化方法,就是遍歷數組,每找到一個局部峰值,然后向前遍歷所有的值,算出共同的矩形面積,每次對比保留最大值。

C++解法一:

 1 // Pruning optimize
 2 class Solution {
 3 public:
 4     int largestRectangleArea(vector<int> &height) {
 5         int res = 0;
 6         for (int i = 0; i < height.size(); ++i) {
 7             if (i + 1 < height.size() && height[i] <= height[i + 1]) {
 8                 continue;
 9             }
10             int minH = height[i];
11             for (int j = i; j >= 0; --j) {
12                 minH = min(minH, height[j]);
13                 int area = minH * (i - j + 1);
14                 res = max(res, area);
15             }
16         }
17         return res;
18     }
19 };

還有一種比較流行的解法,是利用棧來解,詳見http://www.cnblogs.com/lichen782/p/leetcode_Largest_Rectangle_in_Histogram.html,但是經過仔細研究,其核心思想跟上面那種剪枝的方法有異曲同工之妙,這里維護一個棧,用來保存遞增序列,相當於上面那種方法的找局部峰值。

我們可以看到,直方圖形面積要最大的話,需要盡可能的使用連續的矩形多,並且最低一塊的高度要高。有點要木桶原理一樣,總是最低的那塊板子決定桶的裝水量。那么既然需要用單調棧來做,首先要考慮到底用遞增棧,還是用遞減棧來做。

增棧是維護遞增的順序,當遇到小於棧頂元素的數就開始處理,而遞減棧正好相反,維護遞減的順序,當遇到大於棧頂元素的數開始處理。那么根據這道題的特點,我們需要按從高板子到低板子的順序處理,先處理最高的板子,寬度為1,然后再處理旁邊矮一些的板子,此時長度為2,因為之前的高板子可組成矮板子的矩形 ,因此我們需要一個遞增棧,當遇到大的數字直接進棧,而當遇到小於棧頂元素的數字時,就要取出棧頂元素進行處理了,那取出的順序就是從高板子到矮板子了,於是乎遇到的較小的數字只是一個觸發,表示現在需要開始計算矩形面積了,為了使得最后一塊板子也被處理,這里用了個小trick,在高度數組最后面加上一個0,這樣原先的最后一個板子也可以被處理了。由於棧頂元素是矩形的高度,那么關鍵就是求出來寬度,那么跟之前那道Trapping Rain Water一樣,單調棧中不能放高度,而是需要放坐標。由於我們先取出棧中最高的板子,那么就可以先算出長度為1的矩形面積了,然后再取下一個板子,此時根據矮板子的高度算長度為2的矩形面積,以此類推,知道數字大於棧頂元素為止,再次進棧,很是巧妙!關於單調棧問題可以參見http://www.cnblogs.com/grandyang/p/8887985.html

C++解法二:

 1 class Solution {
 2 public:
 3     int largestRectangleArea(vector<int> &height) {
 4         int res = 0;
 5         stack<int> st;
 6         height.push_back(0);
 7         for (int i = 0; i < height.size(); ++i) {
 8             if (st.empty() || height[st.top()] < height[i]) {
 9                 st.push(i);
10             } else {
11                 int cur = st.top(); st.pop();
12                 res = max(res, height[cur] * (st.empty() ? i : (i - st.top() - 1)));
13                 --i;
14             }     
15         }
16         return res;
17     }
18 };

我們可以將上面的方法稍作修改,使其更加簡潔一些:

C++解法二:

 1 class Solution {
 2 public:
 3     int largestRectangleArea(vector<int>& heights) {
 4         int res = 0;
 5         stack<int> st;
 6         heights.push_back(0);
 7         for (int i = 0; i < heights.size(); ++i) {
 8             while (!st.empty() && heights[st.top()] >= heights[i]) {
 9                 int cur = st.top(); st.pop();
10                 res = max(res, heights[cur] * (st.empty() ? i : (i - st.top() - 1)));
11             }
12             st.push(i);
13         }
14         return res;
15     }
16 };

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM