881. Boats to Save People - Explanation

Problem Link

Description

You are given an integer array people where people[i] is the weight of the ith person, and an infinite number of boats where each boat can carry a maximum weight of limit. Each boat carries at most two people at the same time, provided the sum of the weight of those people is at most limit.

Return the minimum number of boats to carry every given person.

Example 1:

Input: people = [5,1,4,2], limit = 6

Output: 2

Explanation:
First boat [5,1].
Second boat [4,2].

Example 2:

Input: people = [1,3,2,3,2], limit = 3

Output: 4

Explanation:
First boat [3].
Second boat [3].
Third boat [1,2].
Fourth boat [2].

Constraints:

  • 1 <= people.length <= 50,000
  • 1 <= people[i] <= limit <= 30,000


Topics

Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Sorting - Understanding how to sort arrays and when sorting enables efficient solutions
  • Two Pointers - Using two pointers from opposite ends of a sorted array to find optimal pairings
  • Greedy Algorithms - Making locally optimal choices (pairing heaviest with lightest) to achieve global optimum

1. Sorting + Two Pointers

Intuition

Since each boat can carry at most two people and has a weight limit, we want to pair the heaviest person with the lightest person when possible. By sorting the weights, we can use two pointers: one at the heaviest person and one at the lightest. If they can share a boat, we move both pointers; otherwise, the heaviest person takes a boat alone.

Algorithm

  1. Sort the people array in ascending order.
  2. Initialize two pointers: left at index 0, right at the last index.
  3. Initialize a boat counter to 0.
  4. While left is less than or equal to right:
    • Calculate the remaining capacity after placing the heaviest person (at right).
    • Decrement right and increment the boat count.
    • If the lightest person (at left) fits in the remaining capacity and left is still valid, increment left.
  5. Return the boat count.
class Solution:
    def numRescueBoats(self, people: List[int], limit: int) -> int:
        people.sort()
        res, l, r = 0, 0, len(people) - 1
        while l <= r:
            remain = limit - people[r]
            r -= 1
            res += 1
            if l <= r and remain >= people[l]:
                l += 1
        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 weights is limited, counting sort can be faster than comparison-based sorting. We count the frequency of each weight, then reconstruct the sorted array. After sorting, we apply the same two-pointer greedy strategy as before.

Algorithm

  1. Find the maximum weight in the array.
  2. Create a count array of size (max + 1) and count the frequency of each weight.
  3. Reconstruct the sorted array by iterating through the count array.
  4. Apply the two-pointer approach:
    • Initialize left at 0 and right at the end.
    • While left is less than or equal to right:
      • The heaviest person takes a boat.
      • If the lightest person fits with them, include them too.
  5. Return the boat count.
class Solution:
    def numRescueBoats(self, people: List[int], limit: int) -> int:
        m = max(people)
        count = [0] * (m + 1)
        for p in people:
            count[p] += 1

        idx, i = 0, 1
        while idx < len(people):
            while count[i] == 0:
                i += 1
            people[idx] = i
            count[i] -= 1
            idx += 1

        res, l, r = 0, 0, len(people) - 1
        while l <= r:
            remain = limit - people[r]
            r -= 1
            res += 1
            if l <= r and remain >= people[l]:
                l += 1
        return res

Time & Space Complexity

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

Where nn is the size of the input array and mm is the maximum value in the array.


Common Pitfalls

Forgetting to Sort the Array First

The two-pointer approach only works on sorted arrays. Attempting to pair people without sorting will not produce the minimum number of boats because you cannot guarantee pairing the heaviest with the lightest.

Trying to Fit More Than Two People per Boat

The problem states each boat can carry at most 2 people, regardless of weight. A common mistake is trying to fit three or more light people in one boat.

# Wrong: trying to fit multiple light people
while l <= r and remain >= people[l]:
    remain -= people[l]
    l += 1  # Might add more than 2 people total

Not Moving the Right Pointer First

The heaviest person always needs a boat. A mistake is checking if the lightest person fits first, which can lead to incorrect pointer movement when the lightest person alone exceeds the remaining capacity.