Skip to main content

Greedy

Boats to Save People Solution In C++/Java/Python/JS

Problem Description

You are given an 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.

Examples

Input: people = [1,2], limit = 3
Output: 1
Explanation: 1 boat (1, 2)

Input: people = [3,2,2,1], limit = 3
Output: 3
Explanation: 3 boats (1, 2), (2) and (3)

Constraints

  • 1 <= people.length <= 5 * 104
  • 1 <= people[i] <= limit <= 3 * 104


The first thing we need to figure out is how to use the least number of boats without going over the weight limit. One smart way is to sort everyone by weight and always try to pair the lightest person with the heaviest one. If they fit together, great — we send them in one boat. If not, the heavier one goes alone. We keep repeating this process until everyone is placed. This simple greedy idea helps us make the most out of each boat and works well even when the input size is large.

Greedy Approach

Intuition

We’re given people with different weights and a limit on how much a boat can carry. Each boat can carry at most two people, but only if their total weight stays within the limit. The goal is to use the least number of boats to carry everyone.
Now before jumping into writing code, think of this like managing space wisely. If two people can share a boat, why send them separately? But obviously, we can’t just pair anyone randomly — we have to be smart about it. So we sort the people by their weights. This helps because we always know who’s the lightest and who’s the heaviest left.
Now the smart move: try to pair the lightest person with the heaviest one. If they fit within the weight limit, send them together. If they don’t, send the heavier person alone — because no one else can go with them anyway. We repeat this process, moving inward from both ends of the sorted list. Every time we do this, we’re making a greedy choice — the best move at that moment without looking too far ahead.
This simple strategy works well because it always tries to make full use of each boat. No extra checks, no wasting time on complex combinations. Just keep making the best move until all the people are on boats.

What is a Greedy Approach and Why It Works Here?

Greedy means we pick the best option available at each step, without thinking too far ahead. In this case, that means always trying to pair the lightest and heaviest person — it’s the most space-efficient move.

Why not try all combinations? Because we don’t need to. If the lightest and heaviest person can’t fit, then no one else can pair with the heaviest, so sending them alone is optimal.

By using two pointers — one from the start and one from the end — we process the list from both sides, pairing whenever possible. This helps us avoid wasting boats and gives us the minimum count in a clean and efficient way.

Example:

people = [1, 2, 2, 3], limit = 3
→ Sort: [1, 2, 2, 3]
→ 1 + 3 = 4 (too much) → send 3 alone
→ 1 + 2 = 3 (fits) → send together
→ send last 2 alone

Total boats = 3

To actually implement this idea, we start by sorting the array of weights. Then we use two pointers — one starting from the beginning (i, pointing to the lightest person) and one from the end (j, pointing to the heaviest). The idea is simple: check if people[i] + people[j] is within the limit. If it is, we move both pointers inward — they share a boat, so we do i++ and j--. But if they can’t fit together, the heavier person at j must go alone, so we just do j--. In both cases, we increase the boats count by 1. This loop continues until all people are placed and i crosses j.
The reason this greedy method works so well is because it always tries to make the most efficient use of the current boat. We never hold back or overthink — we just pick the best move available at that moment.By the end of this process, every person has either shared a boat with someone or gone alone — but always in the best way possible. That’s why this approach gives us the minimum number of boats needed.

Approach

Step 1: Sort the Array
We start by sorting the array of people by their weight.
This helps us efficiently match the lightest and heaviest unassigned individuals to try to fit them on the same boat.
Sorting ensures that we can make optimal pairing decisions as we scan from both ends.

Step 2: Use Two Pointers to Match People
We place two pointers:

  • i: pointing to the lightest person (start of the array)
  • j: pointing to the heaviest person (end of the array)
    At each step:
  • If people[i] + people[j] ≤ limit, they can share a boat → move both pointers (i++, j--)
  • If not, the heavier person must go alone → move only j--
    Each iteration represents one boat being used.

Step 3: Continue Until All People Are Assigned
We repeat the process until i > j, meaning all people are placed into boats.

  • This ensures everyone is accounted for with the minimum number of boats.
  • People are processed exactly once, either paired or solo.

Step 4: Return the Total Boat Count
We maintain a counter to track the number of boats used throughout the process.
After all valid pairings are done, we return this counter as the final answer.
This method guarantees greedy pairing + minimal boat usage in a highly efficient way.

Dry Run

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

Step 1: Sort the People Array

Sorted weights → people = [1, 2, 2, 3]
Initialize two pointers:

  • i = 0 (lightest)
  • j = 3 (heaviest)
  • boats = 0

Iteration 1: i = 0, j = 3

  • Try pairing: people[i] + people[j] = 1 + 3 = 4 → exceeds limit
  • So, person j = 3 (weight 3) goes alone
  • j-- → 2, boats = 1

Iteration 2: i = 0, j = 2

  • Try pairing: 1 + 2 = 3 → within limit
  • Pair them together
  • i++ → 1, j-- → 1, boats = 2

Iteration 3: i = 1, j = 1

  • Only one person left: people[1] = 2
  • Goes alone
  • j-- → 0, boats = 3

Final Output:

  • boats = 3
Code for All Languages
C++
#include <iostream>  // For input and output
#include <vector>    // For using vector
#include <algorithm> // For sort

using namespace std;

class Solution {
public:
    int numRescueBoats(vector<int>& people, int limit) {
        // Step 1: Sort people by their weight
        sort(people.begin(), people.end());

        // Step 2: Use two pointers for pairing
        int i = 0;                    // Pointer to the lightest person
        int j = people.size() - 1;    // Pointer to the heaviest person
        int boats = 0;                // To count how many boats are used

        // Step 3: Pair the lightest and heaviest person if possible
        while (i <= j) {
            // If their combined weight fits in one boat
            if (people[i] + people[j] <= limit) {
                i++; // Move to the next lightest person
            }

            // Always move the heaviest person (they take the boat)
            j--;

            // Use one boat in this step
            boats++;
        }

        // Step 4: Return total boats used
        return boats;
    }
};

int main() {
    int n, limit;

    // Input number of people
    cin >> n;
    vector<int> people(n);

    // Input weights of people
    for (int i = 0; i < n; i++) {
        cin >> people[i];
    }

    // Input weight limit of each boat
    cin >> limit;

    Solution sol;
    int result = sol.numRescueBoats(people, limit);

    // Output the minimum number of boats needed
    cout << result << endl;

    return 0;
}

Java
import java.util.*; // For Scanner and Arrays

class Solution {
    public int numRescueBoats(int[] people, int limit) {
        // Step 1: Sort the array to allow pairing from both ends
        Arrays.sort(people);

        // Step 2: Use two pointers
        int i = 0;                     // Pointer to the lightest person
        int j = people.length - 1;     // Pointer to the heaviest person
        int boats = 0;                 // To count number of boats used

        // Step 3: Try pairing the heaviest with the lightest
        while (i <= j) {
            // If both can go together without exceeding the limit
            if (people[i] + people[j] <= limit) {
                i++; // Move to the next lightest person
            }

            // In any case, move the heaviest person (they take the boat)
            j--;

            // One boat is used in this step
            boats++;
        }

        // Step 4: Return the total number of boats used
        return boats;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // Input the number of people
        int n = sc.nextInt();
        int[] people = new int[n];

        // Input the weights of people
        for (int i = 0; i < n; i++) {
            people[i] = sc.nextInt();
        }

        // Input the boat's weight limit
        int limit = sc.nextInt();

        Solution sol = new Solution();
        int result = sol.numRescueBoats(people, limit);

        // Output the result: minimum boats needed
        System.out.println(result);
    }
}

Python
# Approach: Optimal Greedy Two-Pointer Technique
# Language: Python

class Solution(object):
    def numRescueBoats(self, people, limit):
        """
        :type people: List[int]
        :type limit: int
        :rtype: int
        """

        # Step 1: Sort the array to allow pairing from both ends
        people.sort()

        # Step 2: Use two pointers
        i = 0                      # Pointer to the lightest person
        j = len(people) - 1        # Pointer to the heaviest person
        boats = 0                  # To count number of boats used

        # Step 3: Pair the heaviest and lightest if possible
        while i <= j:
            # If both can go together without exceeding the limit
            if people[i] + people[j] <= limit:
                i += 1  # Move to the next lightest person

            # Always move the heaviest person (they use the boat)
            j -= 1

            # One boat is used in this step
            boats += 1

        # Step 4: Return the total number of boats used
        return boats


if __name__ == "__main__":
    # Input the number of people
    n = int(input())

    # Input the weights of people
    people = list(map(int, input().split()))

    # Input the boat's weight limit
    limit = int(input())

    sol = Solution()
    result = sol.numRescueBoats(people, limit)

    # Output the result: minimum number of boats needed
    print(result)

Javascript
// Approach: Optimal Greedy Two-Pointer Technique
// Language: JavaScript

/**
 * @param {number[]} people - Array of people's weights
 * @param {number} limit - Maximum weight limit per boat
 * @return {number} - Minimum number of boats required
 */
var numRescueBoats = function(people, limit) {
    // Step 1: Sort the array to allow pairing from both ends
    people.sort((a, b) => a - b);

    // Step 2: Initialize two pointers
    let i = 0;                    // Pointer to the lightest person
    let j = people.length - 1;    // Pointer to the heaviest person
    let boats = 0;                // To count how many boats are used

    // Step 3: Try to pair heaviest and lightest
    while (i <= j) {
        // If their combined weight fits the boat
        if (people[i] + people[j] <= limit) {
            i++; // Move to the next lightest person
        }

        // Always move the heaviest person (they take the boat)
        j--;

        // One boat is used in this step
        boats++;
    }

    // Step 4: Return total number of boats used
    return boats;
};

// Driver code to test in Node.js or browser console
(function () {
    const readline = require("readline");

    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });

    const inputLines = [];
    rl.on("line", (line) => {
        inputLines.push(line.trim());
        if (inputLines.length === 3) {
            rl.close();
        }
    });

    rl.on("close", () => {
        const n = parseInt(inputLines[0]); // Number of people
        const people = inputLines[1].split(" ").map(Number); // People's weights
        const limit = parseInt(inputLines[2]); // Boat limit

        const result = numRescueBoats(people, limit);
        console.log(result); // Output the result
    });
})();

Time Complexity : O(n log n)

Sorting the Array — O(n log n)
We begin by sorting the people array to allow optimal pairing.
Let’s denote:

  • n = number of elements in people

The sorting step takes O(n log n) time using any efficient built-in sort function.

Two-Pointer Traversal — O(n)
After sorting, we use two pointers:

  • One from the start (lightest person)
  • One from the end (heaviest person)

Each iteration of the loop processes one or two people.
Since each person is placed in a boat exactly once, the loop runs at most n times, contributing O(n) time overall.

Final Time Complexity: O(n log n)

  • Sorting step → O(n log n)
  • Pairing loop → O(n)
  • Per-iteration work → O(1)

Since sorting dominates, the overall time complexity is: O(nlogn)

Space Complexity: O(1)

Auxiliary Space Complexity: O(1)

This refers to the extra memory used by the algorithm that is not part of the input or output.

In this greedy two-pointer approach, we use only a few integer variables:

  • Two pointers (i and j)
  • One boat counter (boats)

All of these occupy constant space, regardless of the input size.
We do not use any additional data structures like arrays, maps, or lists for computation.
Thus, the auxiliary space complexity is: O(n)

Total Space Complexity: O(n)

This includes:
Input Space:

  • The input array people of length n → contributes O(n)
  • Sorting is performed in place in most languages (like C++, Java, Python), so it doesn’t require extra array storage

Output Space:

  • We return a single integer (number of boats), which is O(1)
  • No result list or complex structure is constructed

Auxiliary Space:

  • As discussed above, this is O(1)

So, the total space used by the algorithm is dominated by the input array: O(n)

Learning Tip

Now we have successfully tackled this problem, let’s try these similar problems.

There are n children standing in a line. Each child is assigned a rating value given in the integer array ratings.You are giving candies to these children subjected to the following requirements:Each child must have at least one candy.Children with a higher rating get more candies than their neighbors.Return the minimum number of candies you need to have to distribute the candies to the children.