问题描述
公司计划面试 2n 人,并需要将每个人分配到两个城市中的一个。每个人飞往城市 A 或城市 B 的费用不同,具体体现在数组 costs 中,其中 costs[i] = [aCosti, bCosti] 代表第 i 个人飞往城市 A 和城市 B 的费用。你需要帮助公司计算将 2n 个人分配到两个城市的最低费用,要求每个城市都有 n 个人到达。
问题分析
每个人有两个选择:飞往城市 A 或者飞往城市 B。每个选择的费用都不同,因此我们需要合理分配这 2n 个人到两个城市,保证每个城市有 n 个人,并且总费用最小。
解题思路
- 计算费用差异:每个人飞往城市 A 或 B 的费用分别是
costs[i][0]和costs[i][1]。计算每个人飞往城市 A 和 B 的费用差异:diff[i] = costs[i][0] - costs[i][1]。如果差异是正的,说明飞往城市 A 更贵,反之则说明飞往城市 B 更贵。 - 排序:我们希望将费用差异小的人分配到两个城市,这样可以避免大额的费用差异影响总费用。因此,我们可以根据每个人的费用差异进行排序,差异小的优先处理。
- 分配人员:排序后,前
n个费用差异较小的人飞往城市 A,剩余的n个人飞往城市 B。这样,尽量让费用差异大的人员选择费用较低的城市。 - 计算总费用:根据排序后的顺序,计算每个人飞往相应城市的费用并求和。
代码实现
import java.util.Arrays;
public class Main {
public static int solution(int[][] costs) {
int n = costs.length / 2;
// 计算费用差异并排序
Arrays.sort(costs, (a, b) -> (a[0] - a[1]) - (b[0] - b[1]));
int totalCost = 0;
// 前 n 个分配到城市 A
for (int i = 0; i < n; i++) {
totalCost += costs[i][0]; // 选择飞往城市 A 的费用
}
// 后 n 个分配到城市 B
for (int i = n; i < 2 * n; i++) {
totalCost += costs[i][1]; // 选择飞往城市 B 的费用
}
return totalCost;
}
public static void main(String[] args) {
int[][] costs1 = {{10, 20}, {30, 20}, {40, 50}, {30, 20}};
int[][] costs2 = {{59, 77}, {48, 54}, {96, 66}, {18, 19}};
int[][] costs3 = {{15, 53}, {41, 73}, {57, 79}, {34, 89}};
System.out.println(solution(costs1) == 90); // 输出: true
System.out.println(solution(costs2) == 192); // 输出: true
System.out.println(solution(costs3) == 201); // 输出: true
}
}
复杂度分析
- 时间复杂度:排序的时间复杂度为
O(n log n),遍历一次数组计算总费用的时间复杂度是O(n)。因此,总时间复杂度为O(n log n)。 - 空间复杂度:主要使用了输入数组的空间,空间复杂度是
O(1),除了输入数据外没有额外的空间使用。
总结
该问题的关键在于通过计算每个人的费用差异并进行排序,优先选择费用差异较小的人进行分配,从而达到最小化总费用的目的。通过这种贪心策略,可以高效地求解问题。