LeetCode 84. Largest Rectangle in Histogram
ver0:
用递归,首先判断整个高度是否单调递增,如果是的话,从第一个高度开始,假设该高度是最终最大矩形的高度,得到面积,一直遍历到最后一个高度,这样就得出了最大面积;如果不是单调递增,则先得到最小高度的位置,根据递归得到最小高度左边的最大矩形面积,再得到最小高度右边的最大矩形面积,又得到以最小高度为最终高度、整体宽度为最终宽度的面积,在这三者中取最大值,即为结果。
16ms
1 class Solution { 2 public: 3 int largestRectangleArea(vector<int>& heights) { 4 if(heights.size() == 0) return 0; 5 return getRes(heights, 0, heights.size()); 6 } 7 int getRes(vector<int>& height, int s, int e){//s:start e:end [start,end) 8 if(s + 1 >= e) return height[s]; 9 int sorted = true; 10 int minH = s; 11 for(int i = s + 1; i < e; ++i){ 12 if(height[i] < height[i-1]) sorted = false; 13 if(height[i] < height[minH]) minH = i; 14 } 15 if(sorted){ 16 int res = 0; 17 for(int i = s; i < e; ++i){ 18 res = max(res, height[i] * (e - i)); 19 } 20 return res; 21 } 22 23 int left = (minH == s) ? 0 : getRes(height, s, minH); 24 int right = (minH == e - 1) ? 0 : getRes(height, minH + 1, e); 25 int res = max(max(left, right), height[minH] * (e - s)); 26 return res; 27 28 } 29 };
ver1:
16ms
另外一种比较易懂的算法。最终最大矩形必定至少包括一个高度条,因此以每个高度条为对象,只要算出包含该高度条的最大矩形,再从这些结果中取最大值,就可以得出整体的最大矩形。那么包含该高度条的最大矩形满足什么条件呢,首先因为最大矩形必定包含该高度条,因此不能出现比该高度条矮的高度条,也就是说,从该高度条向左,最大矩形截止到比该高度条矮的地方(或一直到总体高度的开头),这个比该高度条矮的高度条位置为l,从该高度条向右,最大矩形截止到比该高度条矮的地方(或一直到总体高度的结尾),这个比该高度条的高度条位置为r。综上,这个最大矩形高度为该高度条的高度,宽度为r-l-1(因为l和r都不包括进最大矩形)。
那么如何计算l和r呢,首先说说思路简单但是耗时多的算法。计算l,对于每个高度条heights[i],如果height[i]>height[i-1],那么l=i-1;否则的话,就从i开始一直减到0,找到比height[i]小的高度条。计算r,类似思路。
1 for (int i = 1; i < height.length; i++) { 2 if (height[i] > height[i - 1]) { 3 lessFromLeft[i] = i - 1; 4 } 5 else { 6 int p = i - 1; 7 while (p >= 0 && height[p] >= height[i]) { 8 p--; 9 } 10 lessFromLeft[i] = p; 11 } 12 }
为了改进这个算法,要用上类似动态规划的思想。计算l,对于每个高度条heights[i],如果height[i]>height[i-1],那么l=i-1;否则的话,因为height[p]>=height[i],而height[p]的l必定大于等于height[i]的l,所以此时p可以直接跳到height[p]的l,就不必一个一个比较过去了,而是直接赋值了。
1 while (p >= 0 && height[p] >= height[i]) { 2 p = lessFromLeft[p]; 3 }
注意lessLeft[0]和lessRight[len-1]的初始化,考虑第一个和第二个高度为n、n-1的情况,此时对于第一个高度条,r = 1, r - l - 1 = 1,因此l为-1;倒数第二个和最后一个的高度为n-1、n,最后一个高度条l = len - 2, r - l - 1 = 1,因此r = len。
1 class Solution { 2 public: 3 int largestRectangleArea(vector<int>& heights) { 4 if(heights.size() == 0) return 0; 5 int len = heights.size(); 6 int* lessLeft = new int[len]; 7 lessLeft[0] = -1; 8 int* lessRight = new int[len]; 9 lessRight[len - 1] = len; 10 11 for(int i = 1; i < len; ++i){ 12 if(heights[i - 1] < heights[i]) 13 lessLeft[i] = i - 1; 14 else{ 15 int p = i - 1; 16 while(p >= 0 && heights[p] >= heights[i]) 17 p = lessLeft[p]; 18 lessLeft[i] = p; 19 } 20 } 21 22 for(int i = len - 2; i >= 0; --i){ 23 if(heights[i + 1] < heights[i]) 24 lessRight[i] = i + 1; 25 else{ 26 int p = i + 1; 27 while(p < len && heights[p] >= heights[i]) 28 p = lessRight[p]; 29 lessRight[i] = p; 30 } 31 } 32 33 int area = 0; 34 for(int i = 0; i < len; ++i){ 35 area = max(area, heights[i] * (lessRight[i] - lessLeft[i] - 1)); 36 } 37 return area; 38 39 40 } 41 42 };
还有stack的算法,看不懂,留坑。
https://leetcode.com/discuss/90454/5ms-o-n-java-solution-explained-beats-96%25