*leetcode #84 in cpp

Solution:

Suppose we are at bar i with height h. To form a rectangle with the whole bar i, bar i could form a rectangle with itself, or any adjacent bars with heights >= h. Thus, for each bar i, if bar j is the closest bar to bar i with j < i and height < h, and if bar k is the closets bar to bar i with k > i and height < h, then the area of the rectangle formed by the whole bar i is h * (k-1 - j-1 + 1). We could calculate the area of rectangle formed by each bar i, and find the maximum among them. The maximum would be the maximum area the question asks for. 

A naive solution is :

for each bar i :
int left = i - 1;
int right = i + 1;
while(left >= 0 && heights[left] >= heights[i]) left--; ------------step 1 to find the left bound of the rect
while(right < heights.size() && heights[right] >= heights[i]) right++;--------step 2 to find the right bound of the rect
area = (right - 1 - left - 1 + 1) * heights[i];
But step 1 and 2 is O(n).
To speed these two steps up, we could use two arrays to store bar i's left bound and right bound. (See step 1 and step 2 in the code)

Code: The worst case is still O(n^2)

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        if(heights.empty()) return 0;
        int max_area = -1;
        int cur = 0;
        int m = heights.size();
        int leftBound[m];//leftBound[i] = x, it means height[x] is the first element less than height[i] when scanning from i-1 to 0. 
        int rightBound[m]; //rightBound[i] = x. It means height[x] is the first element less than height[i] when scanning from i + 1 to heights.size() - 1. 
        int left, right; 
        leftBound[0] = -1;
        rightBound[m - 1] = m;
        //construct leftBound[]
        for(cur = 1; cur < m; cur ++){-----------step1
            if(heights[cur-1] < heights[cur]){
                leftBound[cur] = cur - 1;
            }
            else{
                left = cur - 1; 
                while(left >=0 && heights[left] >= heights[cur])
                    left = leftBound[left];
                leftBound[cur] = left;
            }
        }
        //construct rightBound
        for(cur = m - 2; cur >= 0; cur --){-----------step2
            if(heights[cur + 1] < heights[cur])
                rightBound[cur] = cur + 1;
            else{
                right = cur + 1;
                while(right < m && heights[right] >= heights[cur])
                    right = rightBound[right];
                rightBound[cur] = right;
            }
        }
        cur = 0;
        while(cur < m){
            left = leftBound[cur]+1; 
            right = rightBound[cur] - 1;
            max_area = max( (right - left + 1)*heights[cur], max_area);
            cur ++;
        }
        return max_area; 
    }
};

Solution 2 :  Use a stack. 

We use a stack to record the index of the left closest element to current element which is no smaller than current element. 

Given we now scan heights[i].

If height[i] > heights[stack.top()], then we push i into the stack, and proceed to the next i. 

if height[i] <= heights[stack.top()], then we pop out stack.top() to calculate the area formed by height[stack.top()]. 

Code: O(n)

 int largestRectangleArea(vector<int>& heights) {
        heights.push_back(0);
        stack<int> left_ind;
        int max_area = 0;
        int i = 0;
        while(i < heights.size()){
            if(left_ind.empty()) {
                left_ind.push(i);
                i++;
            }
            else{
                if(heights[i] >= heights[left_ind.top()]){
                    left_ind.push(i);
                    i++;
                }else{
                    int left = left_ind.top();
                    left_ind.pop();
                    max_area = max(max_area, heights[left] *(left_ind.empty()?  i  :(i - left_ind.top() - 1)));
                }
            }
            
            
        }
        return max_area; 
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值