「leetcode」1029.两地调度

849 阅读2分钟

原题

公司计划面试 2N 人。第 i 人飞往 A 市的费用为 costs[i][0],飞往 B 市的费用为 costs[i][1]。

返回将每个人都飞到某座城市的最低费用,要求每个城市都有 N 人抵达。

示例:

输入:[[10,20],[30,200],[400,50],[30,20]]
输出:110
解释:
第一个人去 A 市,费用为 10。
第二个人去 A 市,费用为 30。
第三个人去 B 市,费用为 50。
第四个人去 B 市,费用为 20。

最低总费用为 10 + 30 + 50 + 20 = 110,每个城市都有一半的人在面试。

提示:

  • 1 <= costs.length <= 100
  • costs.length 为偶数
  • 1 <= costs[i][0], costs[i][1] <= 1000

思路

本题也是典型的运用贪心算法的题目。我们首先只关注局部,优先选择两地之间价格最低的。

但是这样做可能造成去A,B两个城市人数不平等。我们需要对两个数组进行排序。排序的规则是两个城市价格差值的绝对值从小到大排序。因为当价格差值最小时,对总价格影响也是最小的。

举一个例子


const a = [[10000, 10001], [100, 110], [1, 20]];

const b = [[200, 100]];

如果将20分配给b。b的总价是100 + 20 === 120; a的总价是10000 + 100 === 10100; a和b的总价是10100 + 120 === 10220

如果将10001分配个b。b的总价是10001 + 100 === 10101; a的总价是100 + 1 === 101; a和b的总价是10101 + 101 === 10202

我们判断A和B城市之间人数的多少,使用价格差值绝对值较小的人,去填充人数较少的城市。即可得到最低的费用。

代码


var twoCitySchedCost = function(costs) {
  let aCost = [];
  let bCost = [];
  let aPeople = 0;
  let bPeople = 0;
    
  const sum = (costs, type) => {
    let s = 0;
    costs.forEach(cost => {
      if (type === "A") {
        s += cost[0];
      } else {
        s += cost[1];
      }
    });
    return s;
  };

  for (let i = 0; i < costs.length; i++) {
    if (costs[i][0] > costs[i][1]) {
      bPeople += 1;
      bCost.push(costs[i]);
    } else {
      aPeople += 1;
      aCost.push(costs[i]);
    }
  }
    
  aCost = aCost.sort((a, b) => Math.abs(a[0] - a[1]) - Math.abs(b[0] - b[1]));
  bCost = bCost.sort((a, b) => Math.abs(a[0] - a[1]) - Math.abs(b[0] - b[1]));
    

  if (aPeople > bPeople) {
    bCost = [...bCost, ...aCost.splice(0, costs.length / 2 - bPeople)]
  } else if (aPeople < bPeople) {
    aCost = [...aCost, ...bCost.splice(0, costs.length / 2 - aPeople)]
  }
    
  return sum(aCost, "A") + sum(bCost, "B");
};