算法训练营day30 | {134.加油站, 135.分发糖果, 860.柠檬水找零, 406.根据身高重建队列}
第八章贪心算法part03,遇到两个维度同时要比较的题目,必须先确定一边,再确定另一边。
134. 加油站
- 题目链接:134. 加油站
- 文档讲解:代码随想录
- 视频讲解:贪心算法,得这么加油才能跑完全程!LeetCode :134.加油站
- 状态:想到一个时间复杂度O(n2)的暴力解法。
1.1 解题分析
暴力解法,先计算每个站点的净收益,然后枚举起点,从该起点出发绕一圈,油量不为0。
▶
134. 加油站1 | |
- 换一种思路,首先如果总油量减去总消耗>=0那么一定是可以跑完一圈的。
- 其次,这题贪心在哪里?如果从i出发,在j位置油量变成负数,那么
i~j之间的任意一个点,都不可能成为起点。 - 为什么?假设从i到j的累计和是负数那你如果从i+1、i+2出发,只会更少油,更不可能成功。所以一旦失败,可以跳过一段区间。 只用遍历一遍数组,时间复杂度降低为O(n)。
1
profit[i] + profit[i+1] + ... + profit[j] < 0
▶
134. 加油站1 | |
135. 分发糖果
- 题目链接:135. 分发糖果
- 文档讲解:代码随想录
- 视频讲解:贪心算法,两者兼顾很容易顾此失彼!LeetCode:135.分发糖果
- 状态:没做出来。
2.1 解题分析
题目要求:
- 每个孩子至少分配到 1 个糖果。
- 相邻的孩子中,评分高的孩子必须获得更多的糖果。
但这道题如果两边一起考虑一定会顾此失彼,必须要确定一边之后,再确定另一边。明确解题的顺序。
例如先确定右边评分大于左边的情况(从前往后遍历)。此时局部最优,只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果。局部最优可以推出全局最优。再确定左边大于右边的情况(从后往前遍历),类似的贪心分析方法,不过此时要保证第i个孩子的糖果数量既比大于左边孩子的,又大于右边孩子的,要取最值。
▶
135. 分发糖果1 | |
860. 柠檬水找零
- 题目链接:860.柠檬水找零
- 文档讲解:代码随想录
- 视频讲解:贪心算法,看上去复杂,其实逻辑都是固定的!LeetCode:860.柠檬水找零
- 状态:柠檬水这题,贪心在贪什么?
3.1 解题分析
题目要求在每一步,都能正确找零,保证是合法的;贪心的关键是优先用10元找零,因为5元是万能货币,10元只能给20元找零。并且只能事前决策,不能事后补救。
▶
860. 柠檬水找零1 | |
406. 根据身高重建队列
- 题目链接:406.根据身高重建队列
- 文档讲解:代码随想录
- 视频讲解:贪心算法,不要两边一起贪,会顾此失彼 | LeetCode:406.根据身高重建队列
- 状态:同时要比较身高和排序两个维度,先确定一边再调整另一边。
4.1 解题分析
这题的难点不在想贪心怎么落地,在于Java API,比如二维数组排序、ArrayList怎么转为二维数组。
▶
406. 根据身高重建队列1 | |
5. JAVA API小结
Arrays.fill(arr, 1):快速对数组赋初始值。- 数组排序,一维数组、二维数组,都可以用
Arrays.sort配合自定义比较器的方式。关于比较器Comparetor的固定规则,涉及到升序还是降序:- 返回 < 0 : o1 比 o2 小,o1放前面
- 返回 > 0 : o1 比 o2 大,o1放后面
List<int[]>转int[][]:1
2
3
4int[][] result = new int[people.length][2];
for (int i = 0; i < list.size(); i++) {
result[i] = list.get(i);
}
算法训练营day30 | {134.加油站, 135.分发糖果, 860.柠檬水找零, 406.根据身高重建队列}
http://paopaotangzu.xyz/cn/day30_leetcode/