2037. Minimum Number of Moves to Seat Everyone - Explanation

Problem Link

Description

There are n availabe seats and n students standing in a room. You are given an array seats of length n, where seats[i] is the position of the ith seat. You are also given the array students of length n, where students[j] is the position of the jth student.

You may perform the following move any number of times:

  • Increase or decrease the position of the ith student by 1 (i.e., moving the ith student from position x to x + 1 or x - 1)

Return the minimum number of moves required to move each student to a seat such that no two students are in the same seat.

Note that there may be multiple seats or students in the same position at the beginning.

Example 1:

Input: seats = [2,1,4], students = [3,1,3]

Output: 2

Explanation:

  • The first student is moved from position 3 to position 2 using 1 move.
  • The second student at position 1 is not moved.
  • The third student at position 3 to position 4 using 1 move.
    In total, 1 + 1 = 2 moves are used.

Example 2:

Input: seats = [4,1,5,9], students = [1,3,2,6]

Output: 7

Explanation:

  • The first student is not moved.
  • The second student is moved from position 3 to position 4 using 1 move.
  • The third student is moved from position 2 to position 5 using 3 moves.
  • The fourth student is moved from position 6 to position 9 using 3 moves.
    In total, 0 + 1 + 3 + 3 = 7 moves were used.

Constraints:

  • n == seats.length == students.length
  • 1 <= n <= 100
  • 1 <= seats[i], students[j] <= 100


Topics

Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Sorting Algorithms - Understanding how sorting enables optimal greedy pairing
  • Greedy Algorithms - Matching smallest with smallest to minimize total distance
  • Counting Sort - Linear time sorting when value range is bounded
  • Two Pointers - Traversing two sorted arrays simultaneously

1. Greedy + Sorting

Intuition

To minimize total movement, pair the closest seats with the closest students. Sorting both arrays puts them in order, allowing us to match the i-th smallest student with the i-th smallest seat. This greedy pairing ensures we never have crossing assignments, which would increase total distance.

Why does this work? If we had two students at positions a < b and two seats at positions x < y, pairing (a, y) and (b, x) would create crossing paths. Simple algebra shows |a - x| + |b - y| is always less than or equal to |a - y| + |b - x| when a < b and x < y.

Algorithm

  1. Sort both the seats and students arrays.
  2. For each index i, add the absolute difference between seats[i] and students[i] to the result.
  3. Return the total.
class Solution:
    def minMovesToSeat(self, seats: List[int], students: List[int]) -> int:
        seats.sort()
        students.sort()

        res = 0
        for i in range(len(seats)):
            res += abs(seats[i] - students[i])
        return res

Time & Space Complexity

  • Time complexity: O(nlogn)O(n \log n)
  • Space complexity: O(1)O(1) or O(n)O(n) depending on the sorting algorithm.

2. Counting Sort

Intuition

When the range of positions is bounded, counting sort can be faster than comparison-based sorting. We create frequency arrays for both seats and students, then simulate the sorted pairing by walking through positions from smallest to largest.

Two pointers traverse the count arrays, finding the next available seat and next waiting student. Each match contributes its distance to the res.

Algorithm

  1. Create count arrays for seats and students up to the maximum position.
  2. Use two pointers i and j starting at position 0.
  3. While unmatched pairs remain:
    • Advance i until count_seats[i] > 0.
    • Advance j until count_students[j] > 0.
    • Add |i - j| to res, decrement both counts.
  4. Return the total.
class Solution:
    def minMovesToSeat(self, seats: List[int], students: List[int]) -> int:
        max_index = max(max(seats), max(students)) + 1
        count_seats = [0] * max_index
        count_students = [0] * max_index

        for seat in seats:
            count_seats[seat] += 1
        for student in students:
            count_students[student] += 1
        
        i = j = res = 0
        remain = len(seats)
        while remain:
            if count_seats[i] == 0:
                i += 1
            if count_students[j] == 0:
                j += 1
            if count_seats[i] and count_students[j]:
                res += abs(i - j)
                count_seats[i] -= 1
                count_students[j] -= 1
                remain -= 1
        return res

Time & Space Complexity

  • Time complexity: O(n+m1+m2)O(n + m1 + m2)
  • Space complexity: O(m1+m2)O(m1 + m2)

Where nn is the size of the input arrays, m1m1 is the maximum value in the array seatsseats, and m2m2 is the maximum value in the array studentsstudents.


3. Counting Sort (Optimal)

Intuition

When multiple students are at the same position or multiple seats are at the same position, we can batch process them. Instead of matching one pair at a time, we match min(count_seats[i], count_students[j]) pairs at once, multiplying the distance by the batch size.

This optimization reduces iterations when there are many duplicates, though the asymptotic complexity remains the same.

Algorithm

  1. Create count arrays for seats and students.
  2. Use two pointers i and j starting at position 0.
  3. While unmatched pairs remain:
    • Advance i until count_seats[i] > 0.
    • Advance j until count_students[j] > 0.
    • Compute tmp = min(count_seats[i], count_students[j]).
    • Add |i - j| * tmp to res, decrement counts by tmp.
  4. Return the total.
class Solution:
    def minMovesToSeat(self, seats: List[int], students: List[int]) -> int:
        count_seats = [0] * (max(seats) + 1)
        count_students = [0] * (max(students) + 1)

        def count_sort(arr, count):
            for num in arr:
                count[num] += 1

        count_sort(seats, count_seats)
        count_sort(students, count_students)

        remain = len(seats)
        i = j = res = 0
        while remain:
            if count_seats[i] == 0:
                i += 1
            if count_students[j] == 0:
                j += 1
            if count_seats[i] and count_students[j]:
                tmp = min(count_seats[i], count_students[j])
                res += abs(i - j) * tmp
                count_seats[i] -= tmp
                count_students[j] -= tmp
                remain -= tmp
        return res

Time & Space Complexity

  • Time complexity: O(n+m1+m2)O(n + m1 + m2)
  • Space complexity: O(m1+m2)O(m1 + m2)

Where nn is the size of the input arrays, m1m1 is the maximum value in the array seatsseats, and m2m2 is the maximum value in the array studentsstudents.


Common Pitfalls

Not Sorting Both Arrays

The greedy solution requires sorting both the seats and students arrays before pairing. Sorting only one array or forgetting to sort altogether will produce incorrect results. The optimal pairing matches the i-th smallest student with the i-th smallest seat, which requires both arrays to be in sorted order.

Using Signed Subtraction Instead of Absolute Difference

When calculating the distance between a seat and a student, you must use abs(seats[i] - students[i]), not just seats[i] - students[i]. If a student is at a larger position than their assigned seat, the subtraction would be negative, leading to an incorrect (and possibly negative) total. Always use the absolute value to measure distance.