公司计划面试
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
解法一
//时间复杂度O(n), 空间复杂度O(n)
class Solution {
public:
int twoCitySchedCost(vector<vector<int>>& costs) {
priority_queue<int, vector<int>, greater<int>> negative, positive;//小顶堆
int total_cost = 0, zero_count = 0;
for(auto vec : costs) {
total_cost += min(vec[0], vec[1]);
int diff = vec[0] - vec[1];
if(diff > 0) positive.push(diff);
else if(diff < 0) negative.push(-diff);
else zero_count++;
}
auto& shorter = negative.size() > positive.size() ? positive : negative;
auto& longer = negative.size() > positive.size() ? negative : positive;
int n = (longer.size() - shorter.size() - zero_count) / 2;
while(n--) {
total_cost += longer.top();
longer.pop();
}
return total_cost;
}
};
思路:
不考虑两地人数相等的情况下,先考虑最低费用total_cost,它等于costs中每一对元素 { vec[0], vec[1] }较小者之和。
对于元素对 { vec[0], vec[1] },两地费用差diff = vec[0] - vec[1]。如果diff > 0,暂且称为正对,此时去B地划算;如果diff < 0,暂且称为负对,选A地划算。如果diff = 0,暂且称为零对,去两地费用一样。
解法一使用了两个堆:positive记录正对的费用差,negative记录了负对的费用差(的绝对值)。使用一个计数zero_count记录零对的个数。
最低费用的条件:两个堆的元素数量之差(设差为正)小于zero_count。(因为零对可以充当正对,也可当负对)。
如果不满足最低费用条件,需要对元素数量大的堆的最小元素(小顶堆的堆顶)进行翻转(如正对{10, 20}本来应选A地,费用为10;翻转后选B地,相比最低费用的额外的费用为abs(diff) = 10,也就是20)。每翻转一次,两个堆的元素数量分别会加1、减1,并且要将额外费用加到最低费用total_cost上。反复翻转堆顶元素,直到满足最低费用条件,返回total_cost。
代码如上。
2019/09/08 00:54