Advertisement
Iam_Sandeep

Largest rectangle area in histogram

Jun 15th, 2022 (edited)
928
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.99 KB | None | 0 0
  1. #better go with method 2 than method 1
  2. #Method 1:
  3. '''
  4. The idea is to use a monotonic stack. We iterate over bars and add them to the stack as long as the last element in the stack is less than the current bar. When the condition doesn't hold, we start to calculate areas by popping out bars from the stack until the last element of the stack is greater than the current. The area is calculated as the number of pops multiplied by the height of the popped bar. On every pop, the height of the bar will be less or equal to the previous (since elements in the stack are always monotonically increasing).
  5.  
  6. Now let's consider this example [2,1,2]. For this case the formula for the area (number of pops * current height) won't work because when we reach 1 we will pop out 2 from the stack and will not consider it later which is wrong since the largest area here is equal to 3 * 1, i.e we somehow need to remember the previously discarded bars that still can form areas. We solve this problem by storing in the stack the width of the bar as well. So for our example, after discarding 2, we push to the stack the 1 with the width equal to 2.
  7.  
  8. Time: O(n) - In the worst case we have 2 scans: one for the bars and one for the stack
  9. Space: O(n) - in the wors case we push to the stack the whjole input array
  10.  
  11. Runtime: 932 ms, faster than 51.27% of Python3 online submissions for Largest Rectangle in Histogram.
  12. Memory Usage: 28.4 MB, less than 30.61% of Python3 online submissions for Largest Rectangle in Histogram
  13. '''
  14.  
  15. def largestRectangleArea(self, bars: List[int]) -> int:
  16.     st, res = [], 0
  17.     for bar in bars + [-1]: # add -1 to have an additional iteration
  18.         step = 0
  19.         while st and st[-1][1] >= bar:
  20.             w, h = st.pop()
  21.             step += w
  22.             res = max(res, step * h)
  23. #ans=max(mat[i][0]-dp[i][0],ans)
  24.     ```
  25.         st.append((step + 1, bar))
  26.  
  27.     return res
  28. #Method 2:
  29. #in this method when ever a new element breaks montonic stand we have to pop all elements till  monotonic stack
  30. #become valid and then push the element with last popped index so that it can cover perfectly its window for caluculating i,e. it can also extend the possibility of making rectangle through left of current index by doing this bit change.
  31. class Solution:
  32.     def largestRectangleArea(self, nums: List[int]) -> int:
  33.         ans=0
  34.         q=deque()
  35.         n=len(nums)
  36.         for i,j in enumerate(nums):
  37.             newStart=i
  38.             while q and q[-1][0]>j:
  39.                 h,ind=q.pop()
  40.                 newStart=ind
  41.                 ans=max(ans,h*(i-ind))
  42.             q.append((j,newStart))
  43.         #print(q)
  44.         while q:
  45.             h,ind=q.pop()
  46.             print(h*(n-ind))
  47.             ans=max(ans,h*(n-ind))
  48.         return ans
  49. #Method 3(short):
  50. #Find left immediate max and right immediate max for every element
  51. #now iterate over array and use above info find area of max rectangle
  52. class Solution:
  53.     def maximalRectangle(self, g: List[List[str]]) -> int:
  54.         def find(a):
  55.             q=deque()
  56.             n=len(a)
  57.             pre,pos=[-1]*n,[n]*n#To avoid length=(r-l+1) and make length=(r-l) we decremented and  incremented pre pos vals from 0,n to -1,n-1
  58.             for i,val in enumerate(a):
  59.                 while q and a[q[-1]]>=val:#Top>=cur---> increasing stack
  60.                     idx=q.pop()
  61.                     pos[idx]=i
  62.                 if q:
  63.                     pre[i]=q[-1]
  64.                 q.append(i)
  65.             ans=0
  66.             for i in range(n):
  67.                 ans=max(ans,a[i]*(pos[i]-pre[i]-1))#Since here current index is counted twice in both pos and pre
  68.             return ans
  69.         m,n=len(g),len(g[0])
  70.         a=[0]*n
  71.         ans=0
  72.         for i in range(m):
  73.             for j in range(n):
  74.                 a[j]=(a[j]+1 if g[i][j]=='1' else 0)
  75.             ans=max(ans,find(a))
  76.         return ans
  77.  
  78. #Method 3:
  79. class Solution:
  80.     def largestRectangleArea(self, arr: List[int]) -> int:
  81.         n=len(arr)
  82.         def find_left():
  83.             st=[]
  84.             left=[0]*n
  85.             for i in range(n):
  86.                 if not st:
  87.                     st.append(i)
  88.                 elif arr[st[-1]]<arr[i]:
  89.                     left[i]=st[-1]+1
  90.                     st.append(i)
  91.                 else:
  92.                     while st and arr[st[-1]]>=arr[i]:
  93.                         st.pop()
  94.                     if st:
  95.                         left[i]=st[-1]+1
  96.                     st.append(i)
  97.             return left
  98.            
  99.         def find_right():
  100.             st=[]
  101.             right=[n-1]*n
  102.             for i in range(n):
  103.                 if not st or arr[st[-1]]<=arr[i]:
  104.                     st.append(i)
  105.                 else:
  106.                     while  st and arr[st[-1]]>arr[i]:
  107.                         right[st.pop()]=i-1
  108.                     st.append(i)
  109.             return right
  110.         right,left=find_right(),find_left()
  111.        
  112.         area=0
  113.         for i in range(n):
  114.             r,l,h=right[i],left[i],arr[i]
  115.             area=max(area,(r-l+1)*h)
  116.         return area
  117.                    
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement