Longest Park
Longest Park
Category
Stacks
Difficulty
Hard
Problem Statement
Given an array of building heights along a street, find the longest contiguous "park" segment. A park is defined as a segment between two buildings where all intermediate buildings are strictly shorter than both endpoint buildings. Return the length of the longest such park (including the endpoints). This is solved efficiently using a monotonic stack approach.
Intuition
For each building, we want to know the nearest building to its left and right that is at least as tall. These two taller buildings can serve as endpoints of a park, with the current building and its neighbors forming the interior. A monotonic stack lets us efficiently find, for each position, the nearest greater or equal element on both sides. The park length between two "bounding" buildings is determined by the distance between them.
Approach
- Compute left bounds: Use a monotonic decreasing stack scanning left to right. For each index
i, find the nearest indexj < iwhereheights[j] >= heights[i]. Store inleftBound[i]. - Compute right bounds: Use a monotonic decreasing stack scanning right to left. For each index
i, find the nearest indexk > iwhereheights[k] >= heights[i]. Store inrightBound[i]. - For each index
i, consider it as the minimum of a potential park. The park spans fromleftBound[i]torightBound[i], with lengthrightBound[i] - leftBound[i] + 1. - Return the maximum such length across all indices.
Alternatively, use a single monotonic stack pass:
- Maintain a stack of indices with decreasing heights.
- When pushing index
i, pop all indices with heights less thanheights[i]. For each popped index, the current indexiis its right bound and the new stack top is its left bound. - Track the maximum park length from these bounds.
Pseudocode
function longestPark(heights):
n = length(heights)
leftBound = array of size n, initialized to -1
rightBound = array of size n, initialized to n
maxLength = 0
// Find nearest greater or equal to the left
stack = []
for i from 0 to n - 1:
while stack is not empty and heights[stack.top()] < heights[i]:
stack.pop()
if stack is not empty:
leftBound[i] = stack.top()
stack.push(i)
// Find nearest greater or equal to the right
stack = []
for i from n - 1 down to 0:
while stack is not empty and heights[stack.top()] < heights[i]:
stack.pop()
if stack is not empty:
rightBound[i] = stack.top()
stack.push(i)
// Find longest park
for i from 0 to n - 1:
if leftBound[i] != -1 and rightBound[i] != n:
parkLength = rightBound[i] - leftBound[i] + 1
maxLength = max(maxLength, parkLength)
return maxLength
Time & Space Complexity
- Time: O(n) — Each element is pushed and popped from the stack at most once per pass. Three linear passes total.
- Space: O(n) — For the stack and the boundary arrays.
Key Insights
- The monotonic stack efficiently solves "nearest greater element" queries, which are the foundation of this problem.
- The park definition requires both endpoints to be taller than all interior elements. This maps directly to finding left and right bounds that are greater or equal.
- A single-pass monotonic stack solution is possible but the two-pass version is clearer and has the same asymptotic complexity.
- This problem is structurally related to the largest rectangle in histogram problem, using the same monotonic stack framework.
Edge Cases
- Array with fewer than 3 elements: the minimum valid park is the array itself if it satisfies the constraints, otherwise no park exists.
- All buildings have the same height: every pair of adjacent buildings forms a valid park of length 2.
- Strictly increasing or decreasing heights: parks can only form with the tallest building as one endpoint.
- Multiple parks of the same maximum length: return the length (not the position).
- Single building: no park possible, return 0.