You are given an array of integers heights
representing a histogram where the width of each bar is 1. Your task is to find the area of the largest rectangle that can be fit within the histogram. Imagine you have a series of adjacent bars of varying heights, and you want to determine the biggest rectangular area you can form using these bars.
Here are some examples to illustrate the problem:
heights = [2, 1, 5, 6, 2, 3]
In this case, the largest rectangle has an area of 10. It spans the bars of height 5 and 6.
heights = [2, 4]
Here, the largest rectangle has an area of 4, formed by either the single bar of height 4, or the combination of both bars, where the height is limited by the shorter bar (height 2) times the width (2), resulting in 4.
heights = [6, 2, 5, 4, 5, 1, 6]
In this histogram, the largest rectangle has an area of 12. It spans from the first bar (height 6) to the end of bar with height 1. Since the smallest height between them is bar of height 2. So you cannot find the largest rectangle from it.
Could you provide an algorithm to solve this problem efficiently? Consider the time and space complexity of your solution.
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 approach would be to consider every possible rectangle. For each starting bar, we iterate through all subsequent bars, considering the minimum height between them as the height of the rectangle, and the width as the number of bars considered so far. We keep track of the maximum area encountered.
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])
width = j - i + 1
area = min_height * width
max_area = max(max_area, area)
return max_area
O(n^2), where n is the number of bars in the histogram. This is due to the nested loops.
O(1), as we only use a constant amount of extra space.
The optimal approach uses a stack to keep track of the indices of increasing heights. When we encounter a bar with a height less than the bar at the top of the stack, it means we've found the right boundary for the rectangle defined by the bar at the top of the stack. We pop the stack and calculate the area of that rectangle.
heights
array:
def largestRectangleArea(heights):
max_area = 0
stack = []
n = len(heights)
for i in range(n):
while stack and heights[i] < heights[stack[-1]]:
height = heights[stack.pop()]
width = i - stack[-1] - 1 if stack else i
max_area = max(max_area, height * width)
stack.append(i)
while stack:
height = heights[stack.pop()]
width = n - stack[-1] - 1 if stack else n
max_area = max(max_area, height * width)
return max_area
O(n), where n is the number of bars in the histogram. Each bar is pushed onto and popped from the stack at most once.
O(n), in the worst case, the stack can contain all the indices if the heights are in increasing order.
heights
array is empty, the largest area is 0.