leetcode : Largest Rectangle in Histogram

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.

Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].

 

The largest rectangle is shown in the shaded area, which has area = 10 unit.

 

For example,
Given height = [2,1,5,6,2,3],
return 10.

首先想到的是暴力求解,即对于每一个index = i,分别向左 右两边搜索第一个比它小的值的index,然后求宽度,计算面积。

意料之中的超时了

代码:

class Solution {
public:
    int largestRectangleArea(vector<int> &height) {
        int ret = INT_MIN;
        for(int i = 0; i < height.size(); ++i){
            ret = max(ret, getMax(height, i));
        }
        return ret;
    }
    int getMax(vector<int> &height, int pos){
        int count = 1;
        int left = pos - 1,right = pos + 1;
        while(left >= 0 && height[pos] <= height[left--])
            ++count;
        while(right < height.size() && height[pos] <= height[right++])
            ++count;
        return count * height[pos];
    }
};

开始优化,可以发现,如果height[i]< height[i+1] 那么右边界取i+1面积总会比取i要大。于是可以一直向右遍历,直到遇见height[i]> height[i+1] 这个时候以height[i]为右边界,然后再找左边界。这个方法可以AC,但是还可以做的更好。

// O(n^2) with pruning  
public int largestRectangleArea1(int[] height) {  
  // Start typing your Java solution below  
  // DO NOT write main() function  
  int area = 0;  
  for (int i = 0; i < height.length; i++) {  
    for (int k = i + 1; k < height.length; k++) {  
      if (height[k] < height[k - 1]) {  
        i = k - 1;  
        break;  
      } else {  
        i = k;  
      }  
    }  
    int lowest = height[i];  
    for (int j = i; j >= 0; j--) {  
      if (height[j] < lowest) {  
        lowest = height[j];  
      }  
      int currArea = (i - j + 1) * lowest;  
      if (currArea > area) {  
        area = currArea;  
      }  
    }  
  }  
  return area;  
}

 

在上面的方法,求左边界的时候,每次左边界左移一次,都需要进行一次比较,求一次lowest,那么我们可以只存储height[i]值最小的那个i;

可以维护这样一个栈,栈里存储着递增但不连续的index,同时height[index]是递增的,那么当height[i]小于height[top]的时候,就分别以top,top-1,top-2为最小值,计算最大面积。同时将这些height大于height[i]的节点弹出,同时将i入栈

如果height[i]大于height[top]的话,直接将i进栈。

这样可以保证栈里的所有index 恰好对应了第二个方法中的所有lowest的节点的index。大量减少了比较次数

最终代码:

class Solution {
public:
    int largestRectangleArea(vector<int> &height) {
        stack<int> s;
        int i = 0;
        int maxArea = 0;
        height.push_back(0);
        while(i < height.size()){
            if(s.empty() || height[i] > height[s.top()])
                s.push(i++);
            else{
                int right = s.top();
                s.pop();
                maxArea = max(maxArea, height[right] * (s.empty() ? i : i - s.top() - 1));
            }
        }
        return maxArea;
    }
};

注意if语句的判断条件,height[i]> height[s.top()]而不是 >=,这样可以保证height值相同的节点,栈里也只有一个,如果这些连续相等节点之后还有大量节点的话,会很明显的影响算法效率。使用>是76ms过,用>=是104ms过。

posted on 2014-11-28 11:30  远近闻名的学渣  阅读(180)  评论(0)    收藏  举报

导航