❇️Day 34 第八章 贪心算法 part04
✴️今日任务
- 860.柠檬水找零
- 406.根据身高重建队列
- 452.用最少数量的箭引爆气球
❇️860.柠檬水找零
- 本题看上好像挺难,其实挺简单的,大家先尝试自己做一做。
- 题目链接:https://leetcode.cn/problems/lemonade-change/
- 视频讲解:https://www.bilibili.com/video/BV12x4y1j7DD
- 文章链接:https://programmercarl.com/0860.%E6%9F%A0%E6%AA%AC%E6%B0%B4%E6%89%BE%E9%9B%B6.html
自己的思路
利用switch case语句判断
自己的代码(✅通过100%)
踩坑:
- switch的case需要用break不然会一直执行剩下的case
public boolean lemonadeChange(int[] bills) {int count5 = 0;int count10 = 0;for (int i = 0; i < bills.length; i++) {switch (bills[i]){case 5:count5 ++;break;case 10:count10 ++;if(count5 > 0) count5--;else return false;break;case 20:if(count10 > 0 && count5 > 0){count10 --;count5 --;}else if(count5 >= 3){count5 -= 3;}else{return false;}break;}}return true;
}
随想录思路
和我的基本一样只是换成if-else
随想录代码
public boolean lemonadeChange(int[] bills) {int five = 0;int ten = 0;for (int i = 0; i < bills.length; i++) {if (bills[i] == 5) {five++;} else if (bills[i] == 10) {five--;ten++;} else if (bills[i] == 20) {if (ten > 0) {ten--;five--;} else {five -= 3;}}if (five < 0 || ten < 0) return false;}return true;
}
❇️406.根据身高重建队列
- 本题有点难度,和分发糖果类似,不要两头兼顾,处理好一边再处理另一边。
- 题目链接:https://leetcode.cn/problems/queue-reconstruction-by-height/
- 视频讲解:https://www.bilibili.com/video/BV1EA411675Y
- 文章链接:https://programmercarl.com/0406.%E6%A0%B9%E6%8D%AE%E8%BA%AB%E9%AB%98%E9%87%8D%E5%BB%BA%E9%98%9F%E5%88%97.html
自己的思路
先以ki排序然后再通过hi插入
难点:不会对二维数组进行排序
随想录思路
思路一样
-
按照k为下标重新插入队列就可以了,以图中{5,2} 为例:
-
在按照身高从大到小排序后:
- 局部最优:优先按身高高的people的k来插入。插入操作过后的people满足队列属性
- 全局最优:最后都做完插入操作,整个队列满足题目队列属性
- 整个插入过程如下:
排序完的people: [[7,0], [7,1], [6,1], [5,0], [5,2],[4,4]]
插入的过程:
- 插入[7,0]:[[7,0]]
- 插入[7,1]:[[7,0],[7,1]]
- 插入[6,1]:[[7,0],[6,1],[7,1]]
- 插入[5,0]:[[5,0],[7,0],[6,1],[7,1]]
- 插入[5,2]:[[5,0],[7,0],[5,2],[6,1],[7,1]]
- 插入[4,4]:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
此时就按照题目的要求完成了重新排列。
随想录代码
class Solution {public int[][] reconstructQueue(int[][] people) {// 身高从大到小排(身高相同k小的站前面)Arrays.sort(people, (a, b) -> {if (a[0] == b[0]) return a[1] - b[1]; // a - b 是升序排列,故在a[0] == b[0]的狀況下,會根據k值升序排列return b[0] - a[0]; //b - a 是降序排列,在a[0] != b[0],的狀況会根据h值降序排列});LinkedList<int[]> que = new LinkedList<>();for (int[] p : people) {que.add(p[1],p); //Linkedlist.add(index, value),会將value插入到指定index里。}return que.toArray(new int[people.length][]);}
}
二维数组排序
- 四个方法
- sort(T[] a):对指定数组进行升序排列。
- sort(T[] a, int fromIndex, int toIndex):对指定数组的指定范围升序排列。
- sort(T[] a, Comparator<? supre T> c): 根据指定比较器产生的顺序对指定对象数组进行排序。
- sort(T[] a, int fromIndex, int toIndex, Comparator<? supre T> c): 根据指定比较器产生的顺序对指定对象数组的指定范围进行排序。
- 二维数组按照第一维数组排序
int[][] nums=new int[][]{{1,3},{1,2},{5,1},{4,5},{3,3}};
//方法一,使用比较器
Arrays.sort(nums,new Comparator<int[]>(){@Overridepublic int compare(int[] a,int[] b){// 当第一维相等时比较第二维的if(a[0] == b[0]){return a[1]-b[1];}else{return a[0]-b[0];}}
});// 方法二,使用 lambda 表达式
Arrays.sort(nums,(a,b) -> a[0] == b[0] ? a[1]-b[1] : a[0]-b[0]);
for (int[] num : nums) {System.out.print(Arrays.toString(num));
}
// 结果 : [1, 2][1, 3][3, 3][4, 5][5, 1]
- 二维数组按照第二维数组排序
int[][] nums=new int[][]{{1,3},{1,2},{5,1},{4,5},{3,3}};
//方法一
Arrays.sort(nums,new Comparator<int[]>(){@Overridepublic int compare(int[] a,int[] b){// 当第二维相等时比较第一维的if(a[1] == b[1]){return a[0]-b[0];}else{return a[1]-b[1];}}
});// 方法二,使用 lambda 表达式
Arrays.sort(nums,(a,b) -> a[1] == b[1] ? a[0]-b[0] : a[1]-b[1]);
for (int[] num : nums) {System.out.print(Arrays.toString(num));
}
// 结果 : [5, 1][1, 2][1, 3][3, 3][4, 5]
❇️452. 用最少数量的箭引爆气球
- 本题是一道 重叠区间的题目,好好做一做,因为明天三道题目,都是 重叠区间。
- 题目链接:https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/
- 视频讲解:https://www.bilibili.com/video/BV1SA41167xe
- 文章链接:https://programmercarl.com/0452.%E7%94%A8%E6%9C%80%E5%B0%91%E6%95%B0%E9%87%8F%E7%9A%84%E7%AE%AD%E5%BC%95%E7%88%86%E6%B0%94%E7%90%83.html
自己的思路
就是一个取交集的问题
- 先对二维数组进行排序(根据第一个数字)
- 然后选定第一个范围的右区间A,看后面有几个(n)范围的左区间小于等于A,即可以一下扎破n+1个气球
- 然后再从第n+2个范围开始判断
自己的代码(✅通过84.56%)
踩坑:
用lambda表达式会溢出,排不了序,必须使用比较器
public static int findMinArrowShots(int[][] points) {if(points.length == 1) return 1;int count = 1;Arrays.sort(points, new Comparator<int[]>() {@Overridepublic int compare(int[] points1, int[] points2) {//要升序排序,本来习惯写类似于 return o1.val - o2.val 来实现,这里由于样例中有出现//[[-2147483646,-2147483645],[2147483646,2147483647]] 这样的例子,加减法会溢出,所以只能通过比较来实现if (points1[1] > points2[1]) {return 1;} else if (points1[1] < points2[1]) {return -1;}return 0;}});for(int[] i : points) System.out.println(Arrays.toString(i));int end = 0; //被取右区间的范围下标int start = 1; //被取左区间的下标while(start < points.length){System.out.println("次数:"+count);//重叠if(points[start][0] <= points[end][1]){System.out.println("气球{"+points[start][0]+", "+points[start][1]+"}可同时和气球{"+points[end][0]+", "+points[end][1]+"}一起被扎破");}else{end = start;count ++;}start ++;}return count;
}
随想录思路
为了让气球尽可能的重叠,需要对数组进行排序。
如果气球重叠了,重叠气球中右边边界的最小值 之前的区间一定需要一个弓箭。
随想录代码
/*** 时间复杂度 : O(NlogN) 排序需要 O(NlogN) 的复杂度* 空间复杂度 : O(logN) java所使用的内置函数用的是快速排序需要 logN 的空间*/
class Solution {public int findMinArrowShots(int[][] points) {// 根据气球直径的开始坐标从小到大排序// 使用Integer内置比较方法,不会溢出Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0]));int count = 1; // points 不为空至少需要一支箭for (int i = 1; i < points.length; i++) {if (points[i][0] > points[i - 1][1]) { // 气球i和气球i-1不挨着,注意这里不是>=count++; // 需要一支箭} else { // 气球i和气球i-1挨着points[i][1] = Math.min(points[i][1], points[i - 1][1]); // 更新重叠气球最小右边界}}return count;}
}