Sunday, April 13, 2014

Maximum Area Rectangle In Histogram

Question: Find the maximum rectangle (in terms of area) under a histogram in linear time. I mean the area of largest rectangle that fits entirely in the Histogram.

(Please refer figures before code section for clarity. If I include bar i completely, those figure will tell how much maximum area rectangle I can get.)


Answer: A straightforward answer is to go for each bar in the histogram and find the maximum possible area in histogram for it. Finally find the maximum of these values. This will require O(n^2) time but this will be huge if we have a big histogram with thousands of bars. So we need to have an algorithm of O(n*logn) or O(n).

Lets see if we can find one such solution:

There are a few invariants, we can use for this problem:
  1. If we include bar i, maximum possible height of rectangle including that bar will be h(i), height of that bar.
  2. If we include bar i, maximum possible width of rectangle including that bar will be L+R+1, where:
  • L is number of adjacent bars to the left of ith bar and height greater than or equal to h(i).
  • R is number of adjacent bars to the right of ith bar and height greater than or equal to h(i).
For the figure in question, if we include bar i, we will have max area as given in below pictures.

Now our task remains as follows:
1) Get Li
2) Get Ri
3) Get area of rectangle for bar i: A(i) = h(i) * (Li+Ri+1)
4) Find max value of A(i)

How to get Li:
Li is the number of adjacent bars to the left of ith bar and height greater than h(i). How can we calculate this?

One solution is to for each I, traverse through i to 0 until you get a bar of height less than h(i). This will be an O(n^2) solution to find all the Li.

But we can have a better solution, which works in less than O(n^2). Lets see an example; in example figure, what is the farthest bar greater than or equal to h(9) (h(9) =2 in our case). Here we are seeing that 4th bar is just short of h(9), so we can move left till 5th bar. So we don’t need to compare with 3rd, 2nd and 1st bar in this case.

Similarly, if I want to put a new value in the stack, which points we should compare h(i) to find L? : 10th, 9th and 4 th. Coz if we can include 9th bar, we can certainly include 8th, 7th, 6th and 5th bar as they have height greater than h(9).

Now if I use a stack and put only those bars in stack, which are possible candidates. And pop those values until I get a bar with height less than h(i). Finally Li = (i – TOP-of-stack).


Complexity: In first impression, this solution seems to be having O(n^2) complexity. But if we look carefully, we can just put at the max N bars in stack at any point in time. And we are not pushing any bar twice. So we can pop at most N bar while calculating Li for complete histogram. So work time complexity is O(n+n) = O(2n) = O(n)

How to get Ri:
Similarly as we found Li. Just start from the end in place of beginning.


code ---->


#include<iostream>
#include<stack>

using namespace std ;

void findrect(int arr[],int len){

int area[len] ,i , maximum ,t ;
stack<int> s;

for(i=0;i<len;i++)
    area[i]=1;

// calculating Li

for(i=0;i<len;i++){

    while(!s.empty()){
         if(arr[s.top()]>=arr[i])
            s.pop();
         else
            break ;
    }

    if(s.empty())
        t=-1;
    else
        t=s.top();

    area[i]+=i-t-1;
   s.push(i);
}

// clearing the stack for calculating Ri;

while(!s.empty())
    s.pop();

for(i=len-1 ; i >=0 ;i--){

   while(!s.empty()){
    if(arr[s.top()] >=arr[i])
     s.pop();
     else
        break;
   }

   if(s.empty())
    t=len;
    else
     t=s.top();

area[i]+=t-i-1;
    s.push(i);
}
maximum=arr[0]*area[0];

for(i=1;i<len;i++)
    if(maximum < arr[i]*area[i])
      maximum=arr[i]*area[i];

cout << " max area in histogram is " << maximum  << endl ;
}

int main(){
int arr[]={9,6,2,1,3,5,4,8,3,7} ;
int y = sizeof(arr)/sizeof(arr[0]);
findrect(arr,y);
}

1 comment: