开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情
3.贪心难题
- 此类题目如果从未见过,几乎不太可能独立思考出解决方案,需要多做多总结,甚至即使做过也会遗忘。
- 贪心的难题往往代码很简洁,但是思路却非常难。
3.1.分发糖果
-
LeetCode 链接:leetcode.cn/problems/ca…
-
难点在于贪心的策略,如果在考虑局部的时候想两边兼顾,就会顾此失彼。应分别考虑左侧大于右侧和右侧大于左侧的情况,分为两次遍历:
- 第一次是正向遍历,只比较右边孩子评分比左边大的情况。
- 第二次是反向遍历,只比较左边孩子评分比右边大的情况。如果此时也是正向遍历,根据 ratings[i + 1] 来确定 ratings[i] 对应的糖果,那么每次都不能利用上前一次的比较结果。
class Solution { /** 分两个阶段 1、起点下标1从左往右,只要右边比左边大,右边的糖果 = 左边+1 2、起点下标 ratings.length - 2 从右往左, 只要左边比右边大, 左边的糖果应该取本身的糖果数(符合比它左边大)和右边糖果数 + 1二者的最大值,这样才符合比它左边的大,也比它右边大 */ public int candy(int[] ratings) { int[] candyVec = new int[ratings.length]; Arrays.fill(candyVec, 1); //第一次遍历,正向遍历 for (int i = 1; i < ratings.length; i++) { if (ratings[i] > ratings[i - 1]) candyVec[i] = candyVec[i - 1] + 1; } //第二次遍历,反向遍历 for (int i = ratings.length - 2; i >= 0; i--) { if (ratings[i] > ratings[i + 1]) candyVec[i] = Math.max(candyVec[i], candyVec[i + 1] + 1); } int ans = 0; for (int s : candyVec) { ans += s; } return ans; } }
3.2.根据身高重建队列
-
LeetCode 链接:leetcode.cn/problems/qu…
-
与上述题目思路相同,一定要先考虑一个维度,确定好以后再解决另一个维度,如果两个维度一起考虑一定会顾此失彼,而本题中,如果优先按k考虑,会发现并不符合某个维度,从哪个角度来看都没确定下来,因此应优先确定身高降序排序,后续从高到矮按k插入指定索引处即可。
class Solution { public int[][] reconstructQueue(int[][] people) { // 身高从大到小排(身高相同k小的站前面) Arrays.sort(people, (a, b) -> { if (a[0] == b[0]) return a[1] - b[1]; return b[0] - a[0]; }); LinkedList<int[]> que = new LinkedList<>(); for (int[] p : people) que.add(p[1],p); return que.toArray(new int[people.length][]); } }
3.3.跳跃游戏
-
LeetCode 链接:leetcode.cn/problems/ju…
-
维护最远的距离值,与 数组长度 - 1 比较,符合条件返回 true。
class Solution { public boolean canJump(int[] nums) { int ans = 0; for(int i = 0; i < nums.length - 1; i++){ if(i <= ans) ans = Math.max(ans, i + nums[i]); else break; if(ans >= nums.length - 1) return true; } return ans >= nums.length - 1; } }