Prerequisites
Before attempting this problem, you should be comfortable with:
- Monotonic Stack - The optimal solution uses a monotonic decreasing stack to track visible people efficiently
- Stack Operations - Understanding push, pop, and peek operations for tracking element relationships
1. Brute Force
Intuition
For each person in the queue, we want to count how many people they can see to their right. Person i can see person j if there's no one taller than both of them standing in between. We track the maximum height seen so far as we scan rightward. If the minimum of the current person's height and the person we're checking is greater than the max height between them, they can see each other.
Algorithm
- For each person at index
i, initialize a counter and track the maximum height seen so far. - Iterate through all people to the right (from
j = i + 1ton - 1):- If the minimum of
heights[i]andheights[j]is greater than the max height between them, incrementcnt. - Update the max height to include
heights[j].
- If the minimum of
- Store
cntfor personiand returnres.
class Solution:
def canSeePersonsCount(self, heights: List[int]) -> List[int]:
n = len(heights)
res = []
for i in range(n):
maxi = cnt = 0
for j in range(i + 1, n):
if min(heights[i], heights[j]) > maxi:
cnt += 1
maxi = max(maxi, heights[j])
res.append(cnt)
return resTime & Space Complexity
- Time complexity:
- Space complexity: for the output array.
2. Stack - I
Intuition
A monotonic decreasing stack helps us efficiently find visibility relationships. As we iterate left to right, we pop people who are shorter than the current person since they can now see this taller person as their last visible person. The person remaining on top of the stack (if any) can also see the current person since nothing blocks their view.
Algorithm
- Initialize
resarray with zeros and an empty stack to store indices. - Iterate through
heightsfrom left to right:- While the stack is not empty and
heights[stack[-1]] < h, pop and increment their count (they can see the current person). - If the stack is not empty, the top person can see the current person, so increment their count.
- Push the current index onto the stack.
- While the stack is not empty and
- Return
res.
class Solution:
def canSeePersonsCount(self, heights: List[int]) -> List[int]:
n = len(heights)
res = [0] * n
stack = []
for i, h in enumerate(heights):
while stack and heights[stack[-1]] < h:
res[stack.pop()] += 1
if stack:
res[stack[-1]] += 1
stack.append(i)
return resTime & Space Complexity
- Time complexity:
- Space complexity:
3. Stack - II
Intuition
We can also solve this by iterating from right to left. For each person, we count how many people they can see by popping shorter people from the stack (each popped person is visible). If someone taller remains on the stack after popping, that person is also visible since nothing blocks the view.
Algorithm
- Initialize
resarray with zeros and an empty stack to store heights. - Iterate through
heightsfrom right to left:- While the stack is not empty and
stack[-1] < heights[i], pop and incrementres[i]. - If the stack is not empty after popping, increment
res[i]by1(the first taller or equal person is visible). - Push
heights[i]onto the stack.
- While the stack is not empty and
- Return
res.
class Solution:
def canSeePersonsCount(self, heights: List[int]) -> List[int]:
n = len(heights)
res = [0] * n
stack = []
for i in range(n - 1, -1, -1):
while stack and stack[-1] < heights[i]:
stack.pop()
res[i] += 1
if stack:
res[i] += 1
stack.append(heights[i])
return resTime & Space Complexity
- Time complexity:
- Space complexity:
Common Pitfalls
Using the Wrong Stack Order
This problem requires a monotonic decreasing stack. Using an increasing stack or getting the comparison direction wrong leads to incorrect visibility counts. When iterating left-to-right, pop elements shorter than the current person; when iterating right-to-left, pop elements shorter than the current person as well.
Forgetting to Count the Blocking Person
When a taller person blocks the view, they are still visible to the current person. After popping all shorter people from the stack, if the stack is not empty, the person at the top is also visible. Forgetting to add 1 for this blocking person is a common mistake.
Confusing What to Store on the Stack
You can store either indices or heights on the stack, but you must be consistent. Storing indices allows you to update the result array directly but requires looking up heights. Storing heights simplifies comparisons but requires a different approach to update results.
Misunderstanding the Visibility Condition
Person i can see person j if there is no one between them who is taller than both. This is not the same as "no one taller than person j" or "no one taller than person i". The blocking condition depends on the minimum of the two heights being compared against the maximum height between them.