291. Queue Reconstruction by Height
π LeetCode Problem: 406. Queue Reconstruction by Height
π Difficulty: Medium
π·οΈ Topics: Array, Greedy, Sorting
Problem Statement
You are given an array of people, people, which are the attributes of some people in a queue (not necessarily in order). Each people[i] = [hi, ki] represents the ith person of height hi with exactly ki other people in front who have a height greater than or equal to hi.
Reconstruct and return the queue that is represented by the input array people. The returned queue should be formatted as an array queue, where queue[j] = [hj, kj] is the attributes of the jth person in the queue (queue[0] is the person at the front of the queue).
Example 1:
Input: people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
Output: [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
Explanation:
Person 0 has height 5 with 0 people taller or the same height in front.
Person 1 has height 7 with 0 people taller or the same height in front.
Person 2 has height 5 with 2 people taller or the same height in front.
Person 3 has height 6 with 1 person taller or the same height in front.
Person 4 has height 4 with 4 people taller or the same height in front.
Person 5 has height 7 with 1 person taller or the same height in front.
Example 2:
Input: people = [[6,0],[5,0],[4,0],[3,2],[2,2],[1,4]]
Output: [[4,0],[5,0],[2,2],[3,2],[1,4],[6,0]]
Constraints:
- 1 <= people.length <= 2000
- 0 <= hi <= 10^6
- 0 <= ki < people.length
- It is guaranteed that the queue can be reconstructed.
π³ Visual Understanding - The Queue Problem
The Problem We're Solving:
Input: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
β β β β β β β β β β β β
h k h k h k h k h k h k
Where:
h = height of person
k = number of people IN FRONT who are >= this height
Goal: Arrange these people in a queue (order) such that
each person has EXACTLY k people in front who are >= their height
Understanding the Notation:
Person [7, 0]:
- Height = 7
- k = 0 β "0 people in front who are >= 7"
- This person should be at a position where NO ONE taller/equal is in front
Person [4, 4]:
- Height = 4
- k = 4 β "4 people in front who are >= 4"
- This person should be at a position where EXACTLY 4 people >= 4 are in front
Person [7, 1]:
- Height = 7
- k = 1 β "1 person in front who is >= 7"
- This person should be at a position where EXACTLY 1 person >= 7 is in front
What Does "In Front" Mean?
Queue (left to right):
Position: 0 1 2 3 4 5
[__][__][__][__][__][__]
β
Front of queue
If person X is at position 3:
"In front of X" = positions 0, 1, 2
Example:
Queue: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
For person at position 4 ([4,4]):
People in front: [[5,0], [7,0], [5,2], [6,1]]
How many are >= 4? ALL of them! (5, 7, 5, 6 all >= 4)
Count = 4 β Matches k=4!
Key Observations:
1. Each person is [height, k]
- height: their actual height
- k: count constraint (people >= height in front)
2. We need to RECONSTRUCT the queue
- Input is UNORDERED
- Output must satisfy all k constraints
3. Multiple people can have same height
- [7,0] and [7,1] both have height 7
- But different k values
4. Solution is UNIQUE
- Only ONE correct arrangement exists
π§ The AHA Moment - Why This Order Works
The Brute Force Nightmare:
Try all possible arrangements:
- n! permutations for n people
- For each permutation, verify all k constraints
- This is O(n! Γ n) - IMPOSSIBLE! π°
Example: 6 people β 6! = 720 arrangements to check!
The Key Insight - Greedy with Tall People First
Discovery: What if we process tall people first?
Think about it:
If we place TALL people first:
- They don't care about shorter people behind them!
- Shorter people DON'T COUNT for tall people's k value!
Example:
Person [7, 0]: height 7, k=0
If we place them first, we only count people >= 7 in front
Any shorter people (like height 4, 5, 6) DON'T affect them!
This is the KEY insight! π
Visual Discovery - Why Tall First Works
Let's process people by height (tallest first):
People: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
Sort by height (descending):
[7,0], [7,1], [6,1], [5,0], [5,2], [4,4]
β β β β β β
H=7 H=7 H=6 H=5 H=5 H=4
Now process one by one:
Step 1: Place [7,0]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
k=0 β "0 people >= 7 in front"
Insert at position 0 (beginning)
Queue: [[7,0]]
Step 2: Place [7,1]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
k=1 β "1 person >= 7 in front"
Currently in queue: [7,0] (only 1 person >= 7)
Insert at position 1 (after [7,0])
Queue: [[7,0], [7,1]]
Step 3: Place [6,1]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
k=1 β "1 person >= 6 in front"
Currently in queue: [7,0], [7,1] (both are >= 6)
KEY OBSERVATION:
For height 6, people with height 7 COUNT!
We need 1 person >= 6 in front
Insert at position 1 (between [7,0] and [7,1])
Queue: [[7,0], [6,1], [7,1]]
Step 4: Place [5,0]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
k=0 β "0 people >= 5 in front"
Insert at position 0 (beginning)
Queue: [[5,0], [7,0], [6,1], [7,1]]
Step 5: Place [5,2]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
k=2 β "2 people >= 5 in front"
Currently: [5,0], [7,0], [6,1], [7,1]
People >= 5: [5,0], [7,0], [6,1], [7,1] - all of them!
Need 2 in front β insert at position 2
Queue: [[5,0], [7,0], [5,2], [6,1], [7,1]]
Step 6: Place [4,4]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
k=4 β "4 people >= 4 in front"
Currently: [5,0], [7,0], [5,2], [6,1], [7,1]
People >= 4: ALL of them! (5,7,5,6,7 all >= 4)
Need 4 in front β insert at position 4
Queue: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
FINAL ANSWER! β
Why This Greedy Approach Works
The Magic Property:
When we process tall people first:
1. We place them according to their k values
2. When we place shorter people later:
- We INSERT them at position k
- This DOESN'T affect taller people's k counts!
- Because shorter people don't count for taller people!
Example:
Placed [7,0] at position 0
Later insert [5,0] at position 0
[7,0] moves to position 1
But [5,0] doesn't count for [7,0]'s k value (5 < 7)
So [7,0] still has 0 people >= 7 in front β
This is why greedy works:
- Taller people set up positions
- Shorter people "squeeze in" without breaking constraints! π―
The Sorting Strategy
Sort by TWO criteria:
1. Height (descending): Process tall people first
[7, X], [7, Y], [6, Z], [5, A], [5, B], [4, C]
2. Within same height, k (ascending): Process smaller k first
[7, 0], [7, 1], [6, 1], [5, 0], [5, 2], [4, 4]
β β
Same height β sort by k
Why sort by k within same height?
If both have height 7:
[7,0] should come before [7,1]
Because [7,0] needs 0 people >= 7 in front
And [7,1] needs 1 person >= 7 in front
Processing [7,0] first makes sense!
π΄ Approach 1: Brute Force (Too Slow - For Understanding Only)
π‘ Intuition
"Try all possible arrangements and check each one"
For each permutation of people:
Check if all k constraints are satisfied
If yes, return this arrangement
This helps understand the problem but is TOO SLOW!
π Implementation (Conceptual)
// This is TOO SLOW for actual use!
// Just for understanding the problem
class Solution {
public int[][] reconstructQueue(int[][] people) {
// Generate all permutations
List<int[][]> allPermutations = generatePermutations(people);
// Check each permutation
for (int[][] arrangement : allPermutations) {
if (isValid(arrangement)) {
return arrangement;
}
}
return people; // Should never reach here
}
private boolean isValid(int[][] arrangement) {
// Check if each person's k constraint is satisfied
for (int i = 0; i < arrangement.length; i++) {
int height = arrangement[i][0];
int expectedK = arrangement[i][1];
// Count people in front who are >= this height
int actualK = 0;
for (int j = 0; j < i; j++) {
if (arrangement[j][0] >= height) {
actualK++;
}
}
// If constraint not satisfied, this arrangement is wrong
if (actualK != expectedK) {
return false;
}
}
return true; // All constraints satisfied!
}
}
π Complexity Analysis
Time Complexity: O(n! Γ n)
Generate all permutations: O(n!)
Check each permutation: O(n)
Total: O(n! Γ n)
For n=6: 6! Γ 6 = 4,320 operations
For n=10: 10! Γ 10 = 36,288,000 operations!
WAY TOO SLOW! β οΈ
π’ Approach 2: Greedy with Sorting (Optimal)
π¨ Building Deep Intuition - Step by Step
Let me show you WHY this greedy approach works with detailed reasoning:
Step 1: Why Process Tall People First?
Key Insight: Shorter people are "invisible" to taller people!
Example:
Person A: [7, 0] - height 7, needs 0 people >= 7 in front
Person B: [5, 0] - height 5, needs 0 people >= 5 in front
Scenario 1: Place [7,0] first, then insert [5,0]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Step 1: Place [7,0]
Queue: [[7,0]]
Step 2: Insert [5,0] at position 0
Queue: [[5,0], [7,0]]
Check [7,0]:
People in front >= 7: none (5 < 7, doesn't count!)
Expected k = 0 β CORRECT!
Check [5,0]:
People in front >= 5: none
Expected k = 0 β CORRECT!
Scenario 2: Place [5,0] first, then [7,0]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Step 1: Place [5,0]
Queue: [[5,0]]
Step 2: Where to place [7,0]?
[7,0] needs 0 people >= 7 in front
But we have [5,0] in queue
If we put [7,0] anywhere, position matters for [5,0]!
[5,0] would see [7,0] and its k would change!
This is MESSY! Hard to manage! β
CONCLUSION:
Tall first is EASIER because:
- Tall people set their positions
- Short people insert without affecting tall people
- Clean and simple! β
Step 2: Why Insert at Position k?
When we process person [h, k]:
- k tells us "how many people >= h should be in front"
- All people already in queue are >= h (we sorted tall first!)
- So we need EXACTLY k of them in front
- Therefore: Insert at position k!
Example:
Queue: [[7,0], [7,1], [7,2]]
Now insert [6, 1]:
- height 6, k=1
- People in queue: all height 7 (all >= 6)
- Need 1 person >= 6 in front
- Insert at position 1!
Result: [[7,0], [6,1], [7,1], [7,2]]
Verification:
[6,1] has [[7,0]] in front β 1 person >= 6 β
Step 3: Detailed Example - Why It All Works
People: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
After sorting (height desc, k asc):
[[7,0], [7,1], [6,1], [5,0], [5,2], [4,4]]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Process [7,0]: height=7, k=0
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Insert at position k=0
Queue: [[7,0]]
β position 0
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Process [7,1]: height=7, k=1
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Insert at position k=1
Queue: [[7,0], [7,1]]
β pos 0 β pos 1
Reasoning:
[7,1] needs 1 person >= 7 in front
Currently have [7,0] (which is >= 7)
Position 1 puts [7,0] in front β
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Process [6,1]: height=6, k=1
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Insert at position k=1
Queue: [[7,0], [6,1], [7,1]]
β pos 0 β pos 1 β pos 2
Reasoning:
[6,1] needs 1 person >= 6 in front
Currently: [7,0], [7,1] (both are >= 6)
Position 1 puts EXACTLY 1 person ([7,0]) in front β
Key Observation:
[7,1] was at position 1, now moved to position 2
But [6,1] doesn't affect [7,1]'s k!
[7,1] still has 1 person >= 7 in front ([7,0]) β
Because 6 < 7, so [6,1] doesn't count for [7,1]!
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Process [5,0]: height=5, k=0
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Insert at position k=0
Queue: [[5,0], [7,0], [6,1], [7,1]]
Reasoning:
[5,0] needs 0 people >= 5 in front
Position 0 (beginning) achieves this β
Effect on others:
[7,0] moved from pos 0 to pos 1
Still has 0 people >= 7 in front (5 < 7 doesn't count) β
[6,1] moved from pos 1 to pos 2
Has [5,0] and [7,0] in front, but only [7,0] counts (7 >= 6)
Still 1 person >= 6 in front β
[7,1] moved from pos 2 to pos 3
Has [5,0] and [7,0] in front, but only [7,0] counts
Still 1 person >= 7 in front β
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Process [5,2]: height=5, k=2
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Insert at position k=2
Queue: [[5,0], [7,0], [5,2], [6,1], [7,1]]
Reasoning:
[5,2] needs 2 people >= 5 in front
Currently: [5,0], [7,0], [6,1], [7,1] (all >= 5)
Position 2 puts EXACTLY 2 people in front ([5,0], [7,0]) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Process [4,4]: height=4, k=4
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Insert at position k=4
Queue: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
Reasoning:
[4,4] needs 4 people >= 4 in front
Currently: [5,0], [7,0], [5,2], [6,1], [7,1] (all >= 4!)
Position 4 puts EXACTLY 4 people in front β
FINAL ANSWER: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] β
π Implementation - Clean and Simple
import java.util.*;
class Solution {
public int[][] reconstructQueue(int[][] people) {
// Step 1: Sort people
// - By height (descending): tall people first
// - By k (ascending): smaller k first for same height
Arrays.sort(people, (a, b) -> {
if (a[0] != b[0]) {
return b[0] - a[0]; // Height descending
} else {
return a[1] - b[1]; // k ascending
}
});
// Step 2: Insert people one by one at position k
List<int[]> result = new ArrayList<>();
for (int[] person : people) {
int k = person[1];
result.add(k, person); // Insert at position k
}
// Convert to array and return
return result.toArray(new int[people.length][2]);
}
}
π Complete Dry Run
Input: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
STEP 1: Sort
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
After sorting:
[[7,0], [7,1], [6,1], [5,0], [5,2], [4,4]]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
STEP 2: Insert one by one
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Insert [7,0] at position 0:
result = [[7,0]]
Insert [7,1] at position 1:
result = [[7,0], [7,1]]
Insert [6,1] at position 1:
result = [[7,0], [6,1], [7,1]]
Insert [5,0] at position 0:
result = [[5,0], [7,0], [6,1], [7,1]]
Insert [5,2] at position 2:
result = [[5,0], [7,0], [5,2], [6,1], [7,1]]
Insert [4,4] at position 4:
result = [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
VERIFICATION
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
[5,0] at pos 0: 0 people >= 5 in front β
[7,0] at pos 1: 0 people >= 7 in front (5 doesn't count) β
[5,2] at pos 2: 2 people >= 5 in front ([5,0],[7,0]) β
[6,1] at pos 3: 1 person >= 6 in front ([7,0]) β
[4,4] at pos 4: 4 people >= 4 in front (all) β
[7,1] at pos 5: 1 person >= 7 in front ([7,0]) β
All constraints satisfied! β
π Complexity Analysis
Time Complexity: O(nΒ²)
Sorting: O(n log n)
Inserting n people: O(nΒ²)
- Each insert can be O(n) for ArrayList
- n insertions β O(nΒ²)
Total: O(n log n) + O(nΒ²) = O(nΒ²)
Space Complexity: O(n)
Result list: O(n)
Note: Can be optimized to O(n log n) using more complex data structures (like balanced BST), but O(nΒ²) is acceptable for this problem given constraints.
π‘ Key Insights Summary
The Three Critical Points:
1. Process Tall People First
Why? Shorter people don't affect taller people's k values!
Tall person [7,0]:
Only cares about people >= 7
People with height 6, 5, 4 are "invisible" to them!
This makes the problem simpler! β
2. Insert at Position k
Why? k tells exactly how many should be in front!
Person [h, k]:
- All people in queue so far are >= h (sorted tall first)
- Need k of them in front
- Insert at position k achieves this! β
3. Order Within Same Height Matters
For people with same height, process smaller k first!
Why? [7,0] should come before [7,1]
[7,0] needs 0 people >= 7 in front
[7,1] needs 1 person >= 7 in front
If we place [7,0] first, it naturally satisfies both! β
π― Pattern Recognition
Template for Height-Based Problems
// Pattern: Sort + Greedy Insertion
class Solution {
public TYPE solve(TYPE[][] input) {
// Step 1: Sort with strategy
Arrays.sort(input, (a, b) -> {
// Primary: One dimension (often descending)
if (a[0] != b[0]) return b[0] - a[0];
// Secondary: Other dimension (often ascending)
return a[1] - b[1];
});
// Step 2: Greedy insertion
List<TYPE[]> result = new ArrayList<>();
for (TYPE[] item : input) {
result.add(item[POSITION], item);
}
return result.toArray(...);
}
}
Related Problems
- Russian Doll Envelopes (LC 354)
Similar sorting strategy
- Maximum Height by Stacking Cuboids (LC 1691)
Multi-dimensional sorting
- Merge Intervals (LC 56)
Sorting + greedy merging
β οΈ Common Mistakes
// Mistake 1: Wrong sort order
Arrays.sort(people, (a, b) -> a[0] - b[0]); // β Ascending!
// β CORRECT: Descending
Arrays.sort(people, (a, b) -> b[0] - a[0]);
// Mistake 2: Not sorting by k within same height
Arrays.sort(people, (a, b) -> b[0] - a[0]); // β Missing k sort!
// β CORRECT:
Arrays.sort(people, (a, b) -> {
if (a[0] != b[0]) return b[0] - a[0];
return a[1] - b[1]; // k ascending!
});
// Mistake 3: Inserting at wrong position
result.add(person); // β Adds at end!
// β CORRECT:
result.add(person[1], person); // Insert at position k!
// Mistake 4: Not using List for insertion
int[][] result = new int[n][2];
// Inserting in middle of array is expensive!
// β CORRECT: Use ArrayList for O(n) insertion
List<int[]> result = new ArrayList<>();
π Quick Revision Notes
π― Core Concept
Problem: Reconstruct queue where each person [h,k] has exactly k people >= h in front
Key Insight: Process tall people first! Shorter people don't affect tall people's constraints.
Algorithm: 1. Sort: Height descending, k ascending 2. Insert each person at position k
Why It Works: - Tall first β short people "invisible" to them - Insert at k β exactly k people in front - Maintains all constraints! β
β‘ Quick Implementation
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution {
public int[][] reconstructQueue(int[][] people) {
// Example
// Input:
// [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
// This means:
// [7,0] β A person of height 7 has 0 taller or equal people in front.
// [4,4] β A person of height 4 has 4 taller or equal people in front.
// [7,1] β A person of height 7 has 1 taller or equal person in front.
// And so on...
// Output:
// A correctly arranged queue where each personβs conditions are met.
// Correct Output:
// [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
// Let's break it down step by step to see why this output is correct.
// 1st [5,0] Person of height 5 has 0 taller or equal people in front. β
// 2nd [7,0] Person of height 7 has 0 taller or equal people in front. β
// 3rd [5,2] Person of height 5 has 2 taller or equal people in front (7 and 5).
// β
// 4th [6,1] Person of height 6 has 1 taller or equal person in front (7). β
// 5th [4,4] Person of height 4 has 4 taller or equal people in front (5, 7, 5,
// 6). β
// 6th [7,1] Person of height 7 has 1 taller or equal person in front (7). β
// Why Is This Correct?
// Each personβs k condition is satisfied.
// Every person has exactly k taller/equal people in front of them.
return greedy(people);
}
private int[][] greedy(int[][] a) {
// Approach: no logic, only observation
// step 1: sort by height (descending) and k (ascending)
// initial: { 7, 0 }, { 4, 4 }, { 7, 1 }, { 5, 0 }, { 6, 1 }, { 5, 2 }
// sorted: {7, 0}, {7, 1}, {6, 1}, {5, 0}, {5, 2}, {4, 4}
Arrays.sort(a, (p1, p2) -> {
if (p1[0] != p2[0]) {
return p2[0] - p1[0];
} else {
return p1[1] - p2[1];
}
});
// step 2: process each record and put in correct position
List<int[]> reordered = new ArrayList<>();
for (int[] person : a) {
reordered.add(person[1], person);
}
// step 3: covert to required format which is array
// [[5, 0], [7, 0], [5, 2], [6, 1], [4, 4], [7, 1]]
return reordered.toArray(new int[a.length][2]);
}
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(Arrays
.deepToString(s.reconstructQueue(new int[][] { { 7, 0 }, { 4, 4 }, { 7, 1 }, { 5, 0 }, { 6, 1 }, { 5, 2 } })));
}
}
π Key Points
β Sort: Height DESC, k ASC
β Tall first: Shorter people don't affect them
β Insert at position k: Exactly k people in front
β Time: O(nΒ²), Space: O(n)
β Greedy works because of "invisibility" property
πͺ Memory Aid
"Tall people first, they don't care about shorties!"
"Insert at position k, that's where they fit!"
"Sort desc height, asc k within!"
"Greedy placement, constraints maintain!" β¨
π Congratulations!
You've mastered Queue Reconstruction by Height!
What You Learned:
β
Greedy + Sorting - Powerful combination
β
Two-dimensional sorting - Height then k
β
Insertion strategy - Position k is key
β
Invisibility property - Shorter don't affect taller
β
Why greedy works - Deep understanding
The Beautiful Insight:
Complex Constraint Problem β Simple Greedy Solution
The magic insight:
Shorter people are "invisible" to taller people!
This means:
- Process tall first
- They set their positions
- Short "squeeze in" without breaking constraints
One clever observation β Elegant solution! π―
This is the power of Greedy:
Find the right order to process items
Each step maintains all constraints
Global solution emerges naturally! β¨
Interview Mastery:
When asked about Queue Reconstruction:
1. Understand: "[h,k] means k people >= h in front"
2. Key insight: "Process tall first!
Shorter people don't affect tall people's k values"
3. Sorting strategy: "Height descending, k ascending"
4. Algorithm: "Insert each person at position k
This gives exactly k people in front"
5. Why it works: "Tall people set positions,
short people insert without breaking constraints"
6. Code it: Clean O(nΒ²) solution
Shows complete understanding! π―
You've mastered an elegant greedy algorithm with sorting! πβ¨π―