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

  1. For each person at index i, initialize a counter and track the maximum height seen so far.
  2. Iterate through all people to the right (from j = i + 1 to n - 1):
    • If the minimum of heights[i] and heights[j] is greater than the max height between them, increment cnt.
    • Update the max height to include heights[j].
  3. Store cnt for person i and return res.
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 res

Time & Space Complexity

  • Time complexity: O(n2)O(n ^ 2)
  • Space complexity: O(n)O(n) 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

  1. Initialize res array with zeros and an empty stack to store indices.
  2. Iterate through heights from 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.
  3. 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 res

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

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

  1. Initialize res array with zeros and an empty stack to store heights.
  2. Iterate through heights from right to left:
    • While the stack is not empty and stack[-1] < heights[i], pop and increment res[i].
    • If the stack is not empty after popping, increment res[i] by 1 (the first taller or equal person is visible).
    • Push heights[i] onto the stack.
  3. 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 res

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

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.