Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1029. Two City Scheduling - Leetcode Solution

Problem Description

The Two City Scheduling problem asks you to help an organization minimize travel costs for sending people to two cities for a conference. You are given an array costs where costs[i] = [aCost, bCost] represents the cost of flying the ith person to city A and city B, respectively.

  • There are 2N people in total.
  • You must send exactly N people to city A and N people to city B.
  • Each person must be assigned to exactly one city.
  • Your goal is to minimize the total cost of all flights.

Key constraints: Each person is assigned to exactly one city, and you must split the group evenly between the two cities. There is always at least one valid solution, and you cannot reuse people or assign someone to both cities.

Thought Process

At first glance, it might seem like we need to try all possible ways of dividing the people into two groups of N, which would be a brute-force approach. But that's computationally expensive, especially as the group grows larger.

Instead, we notice that for each person, sending them to city A or city B has a certain cost difference. If we always sent everyone to the cheaper city for them, we might end up with an unbalanced assignment (more than N people in one city).

The key insight is to consider the relative savings for each person between the two cities, and to prioritize sending people to the city where their cost advantage is greatest, while still ensuring an even split.

Solution Approach

We want to minimize the total cost while sending exactly N people to each city. Here is a step-by-step approach:

  1. Calculate cost differences: For each person, compute the difference between the cost of going to city A and city B (costA - costB).
  2. Sort by difference: Sort all people based on this difference. A negative value means it's cheaper to send that person to city A; a positive value means city B is cheaper.
  3. Choose N for each city: After sorting, send the first N people (with the most negative differences) to city A, and the remaining N people to city B.
  4. Sum up the costs: Add up the costs according to the assignments.

This approach works because sorting by the cost difference ensures that we assign people to the city where they offer the greatest savings, while still keeping the split even.

Example Walkthrough

Let's say costs = [[10, 20], [30, 200], [400, 50], [30, 20]]. There are 4 people (2N = 4, so N = 2).

  1. Compute differences:
    • Person 0: 10 - 20 = -10
    • Person 1: 30 - 200 = -170
    • Person 2: 400 - 50 = 350
    • Person 3: 30 - 20 = 10
  2. Sort by difference: Sorted indices: 1 (-170), 0 (-10), 3 (10), 2 (350)
  3. Assign:
    • First N=2: Person 1 and Person 0 to city A
    • Last N=2: Person 3 and Person 2 to city B
  4. Sum costs:
    • Person 1 to A: 30
    • Person 0 to A: 10
    • Person 3 to B: 20
    • Person 2 to B: 50

    Total = 30 + 10 + 20 + 50 = 110

This is the minimum possible cost for assigning 2 people to each city.

Code Implementation

class Solution:
    def twoCitySchedCost(self, costs):
        # Sort by cost difference
        costs.sort(key=lambda x: x[0] - x[1])
        n = len(costs) // 2
        total = 0
        # First N to city A, rest to city B
        for i in range(n):
            total += costs[i][0]
        for i in range(n, 2*n):
            total += costs[i][1]
        return total
      
class Solution {
public:
    int twoCitySchedCost(vector<vector<int>>& costs) {
        sort(costs.begin(), costs.end(), [](const vector<int>& a, const vector<int>& b) {
            return (a[0] - a[1]) < (b[0] - b[1]);
        });
        int n = costs.size() / 2;
        int total = 0;
        for (int i = 0; i < n; ++i) {
            total += costs[i][0];
        }
        for (int i = n; i < 2 * n; ++i) {
            total += costs[i][1];
        }
        return total;
    }
};
      
class Solution {
    public int twoCitySchedCost(int[][] costs) {
        Arrays.sort(costs, (a, b) -> (a[0] - a[1]) - (b[0] - b[1]));
        int n = costs.length / 2;
        int total = 0;
        for (int i = 0; i < n; i++) {
            total += costs[i][0];
        }
        for (int i = n; i < 2 * n; i++) {
            total += costs[i][1];
        }
        return total;
    }
}
      
var twoCitySchedCost = function(costs) {
    costs.sort((a, b) => (a[0] - a[1]) - (b[0] - b[1]));
    let n = costs.length / 2;
    let total = 0;
    for (let i = 0; i < n; i++) {
        total += costs[i][0];
    }
    for (let i = n; i < 2 * n; i++) {
        total += costs[i][1];
    }
    return total;
};
      

Time and Space Complexity

  • Brute-force approach: Would involve checking all possible combinations of N people out of 2N, which is O(C(2N, N)) (combinatorial explosion). This is not practical for large inputs.
  • Optimized approach (sorting):
    • Time Complexity: Sorting the cost differences takes O(N \log N) time, where N is the number of people. Assigning costs is O(N).
    • Space Complexity: O(1) extra space (if sorting is in-place) or O(N) if a new array is created.

The sorting-based solution is efficient and scalable.

Summary

The Two City Scheduling problem is a classic example of using sorting to optimize selection under constraints. By focusing on the cost differences and sorting accordingly, we can efficiently assign people to cities to minimize total cost, while maintaining the required balance. This approach leverages a greedy strategy that is both simple and powerful.