Facebook Pixel

1051. Height Checker

EasyArrayCounting SortSorting
Leetcode Link

Problem Description

You have a line of students who need to be arranged for a school photo. The students should stand in a single line ordered by their heights from shortest to tallest (or equal heights can be in any order among themselves). This is called non-decreasing order.

You're given an array heights that shows the current order of students in line, where heights[i] represents the height of the student at position i (using 0-based indexing).

Your task is to figure out how many students are standing in the wrong position. A student is in the wrong position if their current position differs from where they should be when the line is properly sorted by height.

For example:

  • If heights = [1, 1, 4, 2, 1, 3]
  • The properly sorted order would be [1, 1, 1, 2, 3, 4]
  • Comparing position by position:
    • Position 0: 1 = 1 βœ“ (correct)
    • Position 1: 1 = 1 βœ“ (correct)
    • Position 2: 4 β‰  1 βœ— (wrong)
    • Position 3: 2 = 2 βœ“ (correct)
    • Position 4: 1 β‰  3 βœ— (wrong)
    • Position 5: 3 β‰  4 βœ— (wrong)
  • Total students in wrong positions: 3

The solution approach is straightforward: create a sorted version of the heights array (this represents where students should be standing), then compare it with the original array and count how many positions have different values. The code uses sorted(heights) to get the expected arrangement and then counts mismatches using a generator expression with sum() and zip() to compare corresponding positions.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is recognizing that we need to compare the current arrangement with the ideal arrangement. When students are asked to line up by height in non-decreasing order, there's only one correct arrangement possible - the sorted order.

Think of it this way: if we know what the line should look like (sorted by height) and what it currently looks like, we can simply compare these two arrangements position by position. Any position where the heights don't match means a student is standing in the wrong spot.

The problem essentially boils down to asking: "How different is the current arrangement from the sorted arrangement?" We don't need to actually move students or track which student goes where - we just need to count the differences.

Why does this work? Because when we sort the heights array, we get the "expected" positions for each height value. If a student at position i has a different height than what should be at position i in the sorted array, that student needs to move.

For instance, if we see a tall student at the beginning of the line where a short student should be, we know that position is wrong. By sorting the array and comparing it with the original, we identify all such misplaced positions.

The elegance of this approach lies in its simplicity - rather than trying to simulate the rearrangement process or track individual student movements, we just create the target state (sorted array) and count the mismatches. Each mismatch represents a student who isn't where they should be in the properly ordered line.

Learn more about Sorting patterns.

Solution Approach

The implementation follows a straightforward sorting and comparison strategy:

Step 1: Create the Expected Arrangement

expected = sorted(heights)

We use Python's built-in sorted() function to create a new list containing all the heights in non-decreasing order. This represents where each student should be standing. The sorted() function returns a new list, leaving the original heights array unchanged.

Step 2: Compare and Count Differences

return sum(a != b for a, b in zip(heights, expected))

This line does several things efficiently:

  1. zip(heights, expected) - Pairs up elements from both arrays at corresponding positions. For example, if heights = [1, 2, 3] and expected = [1, 3, 2], then zip() produces pairs: (1,1), (2,3), (3,2).

  2. a != b for a, b in ... - This is a generator expression that compares each pair. For each position, it evaluates to True (which equals 1 in Python) if the heights are different, or False (which equals 0) if they're the same.

  3. sum(...) - Adds up all the boolean values. Since True = 1 and False = 0, this effectively counts how many positions have mismatched heights.

Time Complexity: O(n log n) where n is the number of students. The sorting operation dominates the time complexity.

Space Complexity: O(n) for storing the sorted array expected.

The beauty of this solution is its conciseness - in just two lines, we create the target state and count the differences. The use of zip() and a generator expression makes the comparison elegant and memory-efficient, as it doesn't create an intermediate list of comparison results.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a small example with heights = [2, 1, 3, 1, 2].

Step 1: Create the Expected Arrangement

First, we sort the heights to get the proper order:

  • Original: [2, 1, 3, 1, 2]
  • Sorted: [1, 1, 2, 2, 3]

This sorted array represents where students should be standing - shortest to tallest.

Step 2: Compare Position by Position

Now we compare each position using zip(heights, expected):

PositionCurrent HeightExpected HeightMatch?Count
021βœ—+1
111βœ“+0
232βœ—+1
312βœ—+1
423βœ—+1

Step 3: Count the Mismatches

The comparison a != b produces:

  • Position 0: 2 != 1 β†’ True (counts as 1)
  • Position 1: 1 != 1 β†’ False (counts as 0)
  • Position 2: 3 != 2 β†’ True (counts as 1)
  • Position 3: 1 != 2 β†’ True (counts as 1)
  • Position 4: 2 != 3 β†’ True (counts as 1)

Using sum() on these boolean values: 1 + 0 + 1 + 1 + 1 = 4

Result: 4 students are standing in the wrong positions and need to move for the photo to be properly arranged by height.

Solution Implementation

1class Solution:
2    def heightChecker(self, heights: List[int]) -> int:
3        """
4        Count the number of students standing in the wrong positions.
5      
6        A student is in the wrong position if their height doesn't match
7        the expected height when all students are arranged in non-decreasing order.
8      
9        Args:
10            heights: List of integers representing student heights
11          
12        Returns:
13            Number of students not standing in the correct position
14        """
15        # Create the expected arrangement by sorting heights in non-decreasing order
16        expected_heights = sorted(heights)
17      
18        # Count mismatches between actual and expected positions
19        # zip pairs elements from both lists at corresponding indices
20        # The generator expression evaluates to 1 for mismatches, 0 for matches
21        mismatch_count = sum(
22            actual != expected 
23            for actual, expected in zip(heights, expected_heights)
24        )
25      
26        return mismatch_count
27
1class Solution {
2    /**
3     * Counts the number of students standing in the wrong positions
4     * compared to their expected positions when sorted by height.
5     * 
6     * @param heights Array containing the current heights of students
7     * @return The number of students not in their expected positions
8     */
9    public int heightChecker(int[] heights) {
10        // Create a copy of the original heights array to preserve original order
11        int[] expectedHeights = heights.clone();
12      
13        // Sort the expected heights array in non-decreasing order
14        Arrays.sort(expectedHeights);
15      
16        // Initialize counter for mismatched positions
17        int mismatchCount = 0;
18      
19        // Compare each position in original and sorted arrays
20        for (int i = 0; i < heights.length; i++) {
21            // If height at current position doesn't match expected height
22            if (heights[i] != expectedHeights[i]) {
23                mismatchCount++;
24            }
25        }
26      
27        // Return the total number of mismatched positions
28        return mismatchCount;
29    }
30}
31
1class Solution {
2public:
3    int heightChecker(vector<int>& heights) {
4        // Create a copy of the original heights array to store the expected order
5        vector<int> expected = heights;
6      
7        // Sort the expected array to get the correct non-decreasing order
8        sort(expected.begin(), expected.end());
9      
10        // Initialize counter for mismatched positions
11        int mismatchCount = 0;
12      
13        // Compare each position between original and expected arrays
14        for (int i = 0; i < heights.size(); ++i) {
15            // Increment counter if heights don't match at current position
16            if (heights[i] != expected[i]) {
17                mismatchCount++;
18            }
19        }
20      
21        // Return the total number of students in wrong positions
22        return mismatchCount;
23    }
24};
25
1/**
2 * Counts the number of students who are not standing in the correct position
3 * when arranged by height in non-decreasing order.
4 * 
5 * @param heights - Array of student heights
6 * @returns The number of students in wrong positions
7 */
8function heightChecker(heights: number[]): number {
9    // Create a copy of heights array and sort it in ascending order
10    // This represents the expected order of students by height
11    const expectedOrder: number[] = [...heights].sort((a: number, b: number) => a - b);
12  
13    // Count how many positions have different values between original and expected arrays
14    // For each index, increment counter if the height doesn't match expected position
15    const mismatchCount: number = heights.reduce(
16        (accumulator: number, currentHeight: number, index: number) => {
17            // Add 1 if current height doesn't match expected height at this position, otherwise add 0
18            return accumulator + (currentHeight !== expectedOrder[index] ? 1 : 0);
19        },
20        0 // Initial value for accumulator
21    );
22  
23    return mismatchCount;
24}
25

Time and Space Complexity

Time Complexity: O(n Γ— log n)

The time complexity is dominated by the sorted() function, which uses Timsort algorithm with a time complexity of O(n Γ— log n) where n is the number of elements in the heights list. The subsequent operations - zip() and sum() with comparison - both take O(n) time, but since O(n Γ— log n) + O(n) = O(n Γ— log n), the overall time complexity remains O(n Γ— log n).

Space Complexity: O(n)

The space complexity is O(n) because the sorted() function creates a new list called expected that contains all n elements from the original heights list. The zip() operation creates an iterator that doesn't require additional space proportional to the input size, and the generator expression in sum() processes elements one at a time without storing them all in memory.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

Pitfall 1: Attempting to Sort In-Place

A common mistake is trying to sort the original array in-place and then comparing it with itself, which would always result in 0 mismatches:

Incorrect Approach:

def heightChecker(self, heights: List[int]) -> int:
    original = heights  # This doesn't create a copy!
    heights.sort()      # Sorts in-place, modifying the original
    return sum(a != b for a, b in zip(original, heights))  # Always returns 0

Why it fails: In Python, original = heights creates a reference to the same list object, not a copy. When heights.sort() is called, both original and heights point to the same sorted list.

Solution: Always create a copy when you need to preserve the original order:

def heightChecker(self, heights: List[int]) -> int:
    original = heights.copy()  # Or heights[:] or list(heights)
    sorted_heights = sorted(heights)  # Or use this to create a new sorted list
    return sum(a != b for a, b in zip(original, sorted_heights))

Pitfall 2: Misunderstanding the Problem - Counting Unique Heights

Some might misinterpret the problem as counting how many distinct heights are out of order:

Incorrect Interpretation:

def heightChecker(self, heights: List[int]) -> int:
    # Wrong: Counting unique values that are misplaced
    return len(set(heights) - set(sorted(heights)))  # This is incorrect!

Why it fails: The problem asks for the number of positions (indices) where students are wrong, not the number of unique heights that are misplaced. If heights = [1, 1, 4, 2, 1, 3], we need to count 3 positions that are wrong, not unique values.

Solution: Stick to position-by-position comparison as shown in the correct implementation.

Pitfall 3: Off-by-One Errors When Manually Iterating

When implementing the comparison loop manually, indexing errors are common:

Error-Prone Approach:

def heightChecker(self, heights: List[int]) -> int:
    expected = sorted(heights)
    count = 0
    for i in range(len(heights) + 1):  # Wrong: goes beyond array bounds
        if heights[i] != expected[i]:
            count += 1
    return count

Solution: Use zip() to avoid index management entirely, or ensure proper range bounds:

# Better: Let zip handle the pairing
return sum(a != b for a, b in zip(heights, sorted(heights)))

# Or if using indices, ensure correct range
for i in range(len(heights)):  # Correct range
    if heights[i] != expected[i]:
        count += 1
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More