LeetCode 881, Boats to Save People, is a commonly asked interview problem at top tech companies like MAANG, specifically Amazon, Google, and Meta. It tests a candidate’s ability to justify greedy decisions and implement an efficient two-pointer solution under real-world constraints.
Problem statement
You are given an integer array people, where people[i] represents the weight of the ithi^{th}ith person, and an unlimited number of boats, where each boat can carry a maximum weight of limit. A single boat can take at most two people, as long as their combined weight does not exceed limit.
Your task is to compute the minimum number of boats required to carry everyone.
Constraints:
- 1 <=
people.length<= 5 * 104 - 1 <=
people[i]<=limit<= 3 * 104
Examples
| Input | Output | Explanation |
| [5, 10], 15 | 1 | Put 5 and 10 together (5 + 10 ≤ 15). |
| [2, 4, 5, 3], 6 | 3 | One optimal assignment: Pair (2, 4), and (3) and (5) must go alone. |
| [5, 5, 5, 5], 5 | 4 | No valid pairs, so everyone goes alone. |
| [2, 2, 2, 2], 4 | 2 | Pair them as (2, 2) and (2, 2). |
| [1, 1, 1, 1, 7], 7 | 3 | The 7 must go alone; others pair up as: (1,1) and (1,1). |
Naive approach: Trying all valid boat assignments
To find the minimum number of boats in a straightforward way, we can try every valid assignment of people to boats. Since each boat can carry at most two people and their combined weight must be ≤ limit, we pick a person and either send them alone or pair them with any other person who can fit with them.
After making that choice, we recurse on the remaining people and keep track of the smallest number of boats used across all possible choices. This works because it explores all possibilities, but it quickly becomes impractical because the number of ways to form pairings grows combinatorially as the input size increases.
An optimal solution using two pointers + greedy technique
Instead of exploring every possible pairing like the naive recursive approach, we can cut down the search by making a single, safe choice at each step. The key observation is that the heaviest person is the hardest to place, so we handle them first and try to pair them in the most efficient way. For a heavy person, the best partner to attempt is always the lightest remaining person, because that uses the least extra weight and gives the best chance of fitting within the limit. If lightest+heaviestlightest + heaviestlightest+heaviest is still too large, then the heaviest can’t pair with anyone at all, so they must go alone; otherwise, we pair them and continue with the rest.
To do the pairing reliably, we sort the weights. Sorting always keeps the lightest person at the start and the heaviest at the end. It then naturally gives us a two-pointer setup: one pointer for the lightest and the other for the heaviest.
This becomes a greedy technique because at each step we make the safest optimal choice: pair the heaviest with the lightest if possible (best chance to save a boat), otherwise send the heaviest alone (as they can’t pair with anyone). Each step is final, pointers move inward, and the boat count is minimized. In both cases, the pointers move inward until everyone is assigned, giving the minimum number of boats.
Step-by-step algorithm
- Sort
peoplein the ascending order. - Initialize two pointers:
left = 0for the lightest person, andright = n - 1for the heaviest person. Set the number of boats used asboats = 0. - While
left <= right:- Use one boat,
boats += 1, for the heaviest person atright. - Try pairing the heaviest (
people[right]) with the lightest person (people[left]). Ifpeople[left] + people[right] <= limit, pair them and incrementleftto move it inward. - As the heaviest person is always taken, decrement
rightto move it inward.
- Use one boat,
- Once the entire
peoplearray is traveresed, returnboats.
Python code for the optimal solution
Now, let’s take a look at the Python code implementation of this solution:
Time complexity
Sorting takes O(nlogn), and the two-pointer scan takes O(n). So, the overall time complexity for the optimal solution is O(nlogn).
Space complexity
We use Python’s sort function that is based on Tim Sort, which takes O(n) space for the sorting. Other than this, no extra space is used, so the overall space complexity is O(n).
Common mistakes to avoid and interview tips
This problem is greedy, but interviewers mainly want to see that your greedy choice is justified and your pointer movement is correct.
- Don’t try to optimize pairing beyond the two-pointer logic; it usually adds bugs.
- Always move the
rightpointer every loop, because the heaviest person is always placed. - Use
<= limit(not< limit) when checking if two people can share a boat. - Be ready to explain: If the heaviest can’t pair with the lightest, they can’t pair with anyone. That’s the key correctness argument.