406. Queue Reconstruction by Height
On LeetCode ->Problem¶
Given people as pairs \([h, k]\), reconstruct a queue where each person has exactly \(k\) people of height at least \(h\) before them.
Key trick¶
Process taller people first by sorting by decreasing height and increasing \(k\), then insert each person at index \(k\).
Trap¶
- Sorting equal-height people by decreasing \(k\) breaks the insertion invariant.
- Building from shorter people first is difficult because later insertions can change their counts.
- List insertion makes the solution \(O(n^2)\), which is acceptable for the given limit.
Why is it interesting?¶
It turns a global queue constraint into a local insertion decision by ensuring that every person already placed is at least as tall as the current person.
Python solution¶
class Solution:
def reconstructQueue(self, people: list[list[int]]) -> list[list[int]]:
# Taller people are unaffected by later insertions of shorter people.
# For equal heights, place smaller k values first.
ordered = sorted(people, key=lambda person: (-person[0], person[1]))
queue = []
for person in ordered:
# All existing people are at least as tall, so index k gives
# exactly k qualifying people before this person.
queue.insert(person[1], person)
return queue
Sorting costs \(O(n \log n)\); list insertions cost \(O(n^2)\) overall.
Comment on my solution¶
The backtracking approach is exponential and cannot handle up to \(2000\) people.
It also has correctness issues:
- The base case compares the growing queue with the shrinking input, so it may trigger halfway through.
- A successful recursive result is ignored instead of being propagated.
- The returned queue is later emptied during backtracking because it is the same mutable list.
- Each feasibility check builds a temporary list, adding unnecessary work.
- Debug printing makes an already expensive search substantially slower.
# WRONG
class Solution:
def reconstructQueue(self, people: list[list[int]]) -> list[list[int]]:
# [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
# -> [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
# - people[i] = [hi, ki]
# => j for people[i] must be >= ki
# => and for each t <= j, exactly ki, such [ht, kt] with ht >= hi
# - sort descending people of first key
# - [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
# -> [[7, 0], [7, 1], [6, 1], [5, 0], [5, 2], [4, 4]]
# - seems to be pair comparison of pairs
# - the property is global
# - could greedy work with a few swaps and comparison???
# - frequency count somewhere???
# - buckets + backtracking + pruning
# [[[5, 0], [7, 0]],
# [[6, 1], [7, 1]],
# [[5, 2]],
# [],
# [4, 4]]
# let's try backtracking with pruning
people.sort(key=lambda x: x[1])
queue = []
def can_append_to_queue(h,k):
return len(list(filter(lambda x: x[0] >= h, queue))) == k
def backtrack():
if len(queue) == len(people):
return queue
for i, (h, k) in enumerate(people):
if can_append_to_queue(h,k):
people.pop(i)
queue.append([h,k])
backtrack()
people.insert(i,[h,k])
queue.pop()
backtrack()
return queue