LeetCode进阶-1029(贪心)

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

闲聊

不知不觉,从开始发算法博客到如今已经过了半月,在这个过程中其实也遇到过很多困难,也一度想过要放弃,深刻体会到没有任何一件事情是可以简简单单敷衍过去的,特别能体会那些工作之余还能十年如一日坚持技术文章创作的作者们的不容易。不过尽管辛苦也有很多收获,比如精益求精,更追求更完美,又比如收获了很多技术以外的知识,认识了更多的朋友,视野也更加开阔。犹记得第一次投稿成功,第一次文章被大的专栏收录,第一次有人点赞,第一次有粉丝关注,甚至第一次某平台粉丝破百的时候内心的喜悦... 未来,希望自己能把算法博客当成爱好一直写下去,也希望这些文章能给有需要的朋友带来实际的帮助。在后续博文推送过程中,不排除也有些疏漏或者思维理解上的误区,欢迎交流或批评指正。

概要

上一篇博客《LeetCode进阶944-贪心》,有朋友提出建议944对理解贪心算法并不具有很强的代表性。回顾了下上篇的内容,实际文中博主重点说明的是算法优化的小技巧,题解思路也仅仅只是简单的统计法,对贪心思想实际帮助确实不大。基于此博主已将上篇博客标题更正为《LeetCode进阶944-算法优化》(除订阅号由于微信公众平台的限制,标题暂时无法修改),而本篇将以leetcode1029为实例,讲解贪心算法思想。

原题

1029. Two City Scheduling

There are 2N people a company is planning to interview. The cost of flying the i-th person to city A is costs[i][0], and the cost of flying the i-th person to city B is costs[i][1].

Return the minimum cost to fly every person to a city such that exactly N people arrive in each city.

Example 1:

Input: [[10,20],[30,200],[400,50],[30,20]] Output: 110 Explanation: The first person goes to city A for a cost of 10. The second person goes to city A for a cost of 30. The third person goes to city B for a cost of 50. The fourth person goes to city B for a cost of 20.

The total minimum cost is 10 + 30 + 50 + 20 = 110 to have half the people interviewing in each city.

Note:

1 <= costs.length <= 100 It is guaranteed that costs.length is even. 1 <= costs[i][0], costs[i][1] <= 1000

1029. 面试安排(据题意命名)

公司安排2N个人参加面试。第i个人坐飞机飞到城市A的费用为costs[i][0],飞到城市B的费用为 costs[i][1]。

返回安排好每个人都前往某城市面试的最低费用,A、B城市各有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

  • 本题在LeetCode上属于贪心算法分类下

题意分析

需要将2N个人分成两组,分别送往A、B城市面试,每个人去A、B城市的费用已知,要保证总费用最少。凡事涉及最大最小值求和相关的题型,自然不难联想到贪心算法思想,贪心思想最典型的问题是“背包问题”,关于贪心思想需要注意的是,一定要确保“贪心”的思路正确即能拿到最优解,实践过程中可以具体进行数值带入验证。

思路设计

根据题意,需要的最优解是花费最少的钱分别安排N个人前往A、B面试,每个人前往A、B城市的花费有个价格差。可以这简单这么理解我们可以统一计算出每个人前往B城市比前往A城市需要多花的钱(也可以是前往A城市比前往B城市要多花的钱),然后进行排序,价格差最大的排名第一的人必然只能安排到A城市,这样能省下的成本费用最大。接着依次往后安排,排第二的人也只能安排到A城市,一直到安排了排第N的人到A城市,剩下的N个人由于前往B城市比前往A城市花费没那么高全部排到B城市。

伪代码

  1. 1、新建一个大小和人数一致的int数组sort,用于保存每个人前往B城市比前往A城市多花费的费用(注意费用可以是负数,负数等价理解花费更少);

  2. 2、遍历costs花费数组,将差值记录在sort数组元素中;

  3. i.计算第i个人前往B和前往A的差值;

  4. ii.差值左移8位;

  5. iii.左移后加上当前在cost数组中的下标位置i;

  6. 3、对差值sort数组进行排序;

  7. 4、声明一个int变量min表示最小花费总和,循环遍历sort数组,遍历次数只需人数的一半costs.length/2;

  8. i.对于差值排名前N,即sort中最后的N个人,选择去A城市的花费,根据sort元素存储的在costs数组中的下标位置从costs数组中获取去A城市的花费;

  9. ii.对于差值排名后N,即sort中前N个人,选择去B城市的花费,根据sort元素存储的在costs数组中的下标位置从costs数组中获取去B城市的花费;

  10. iii.min累加所有总花费;

编码实践

  1. public int twoCitySchedCost(int[][] costs) {

  2. int sort[] = new int[costs.length];

  3. for (int i = 0; i < costs.length; ++i) {

  4. sort[i] = ((costs[i][1] - costs[i][0]) << 8) + i;

  5. }

  6. Arrays.sort(sort);

  7. int min = 0;

  8. for (int i = 0; i < sort.length / 2; ++i) {

  9. int index1 = sort[costs.length - 1 - i] & 0xFF;

  10. int index2 = sort[i] & 0xFF;

  11. min = min + costs[index1][0] + costs[index2][1];

  12. }

  13. return min;

  14. }

LeetCode进阶-1029(贪心)

彩蛋

观察上面实现代码会发现在sort数组中存储前往B和A城市int差价和在costs数组中下标位置时,使用了左移8位再加i的操作,这便是本文的彩蛋,所有彩蛋均会在后续推文中统一说明。

结语

本文重点在与列举1029实例展示对贪心思想的理解,思路相对简单易于理解,并且从提交结果可以看出贪心思想算法的实践代码效率已经击败了99%的算法,故对另外解法穷举法便不做详细说明,读者可以考虑自己使用穷举法进行实现。关于leetcode进阶系列博客,后续也会疏理出一篇比较系统的进阶大纲,敬请期待^_^

LeetCode进阶-1029(贪心)

扫一扫 关注我的微信订阅号


原文始发于微信公众号(Aeiric):LeetCode进阶-1029(贪心)