Given an array of integers heights
representing a histogram's bar heights, where each bar has a width of 1, find the area of the largest rectangle in the histogram.
For example, consider a histogram represented by the array heights = [2, 1, 5, 6, 2, 3]
. The largest rectangle in this histogram has an area of 10 (formed by the bars of heights 5 and 6).
Here are a few examples:
heights = [2, 1, 5, 6, 2, 3]
Output: 10
heights = [2, 4]
Output: 4
Could you explain your approach to solving this problem, considering both a naive solution and a more optimal solution? Also, discuss the time and space complexity of each approach. Make sure to explain how you handle edge cases.
Given an array of integers heights
representing the histogram's bar height where the width of each bar is 1
, return the area of the largest rectangle in the histogram.
The brute force solution is to consider every possible rectangle that can be formed within the histogram. For each pair of bars i
and j
(where i <= j
), we find the minimum height bar between these two indices. The area of the rectangle formed by these bars is then min_height * (j - i + 1)
. We iterate through all possible i
and j
pairs, calculate the area for each, and keep track of the maximum area found so far.
def largestRectangleArea_brute_force(heights):
max_area = 0
n = len(heights)
for i in range(n):
for j in range(i, n):
min_height = min(heights[i:j+1])
max_area = max(max_area, min_height * (j - i + 1))
return max_area
The outer loop runs n
times, and the inner loop also runs approximately n
times. The min
operation within the inner loop takes O(n) in the worst case. Therefore, the overall time complexity is O(n^3).
The space complexity is O(1) as we use only a constant amount of extra space.
A more efficient solution utilizes a stack. The idea is to maintain a stack of increasing bar indices. When we encounter a bar that is shorter than the bar at the top of the stack, it means we've found the right boundary for the rectangle formed by the bar at the top of the stack. We pop the top of the stack and calculate the area of the rectangle. The width of this rectangle is determined by the current index and the index of the bar before the popped bar in the stack.
heights
array.def largestRectangleArea(heights):
stack = []
max_area = 0
n = len(heights)
for i in range(n):
while stack and heights[i] < heights[stack[-1]]:
height = heights[stack.pop()]
width = i if not stack else i - stack[-1] - 1
max_area = max(max_area, height * width)
stack.append(i)
while stack:
height = heights[stack.pop()]
width = n if not stack else n - stack[-1] - 1
max_area = max(max_area, height * width)
return max_area
The time complexity is O(n), where n is the number of bars. Each bar is pushed onto the stack and popped from the stack at most once.
The space complexity is O(n) in the worst-case scenario, such as when the histogram bars are in increasing order, and all indices are stored in the stack.