描述:若干个气球摆放在二维坐标上,每个气球的开始和结束位置用二维数组给出,求用最少的弓箭射爆最多数量的气球(尽量射到重叠的气球)
解决:局部最优:从气球重叠数量最多的位置射出,所用的弓箭数量最少,全局最优:把所有气球射爆所用弓箭最少。
1. 根据气球的开始位置给气球排序
2. 遍历每个气球,判断是否跟前一个气球发生重叠
- 如果发生重叠,更新最小的结束坐标,说明从这个坐标出发能射爆最多的重叠气球
- 如果不发生重叠,射出的弓箭数+1,把之前重叠的气球射掉,然后更新新的重叠气球的结束坐标
- 最后弓箭数+1, 射掉最后一组气球
问题分析:
在排序过程中,常见的lambda表达式这样写
//o1 和 o2 是points数组的两个相邻元素,取o1的第一个元素和o2的第一个元素比,如果差值大于0,表示前者大,需要发生交换
Arrays.sort(points, (o1, o2) -> (o1[0] - o2[0]);
但是如果出现这种情况:
用例:[[-2147483646,-2147483645],[2147483646,2147483647]]
该用例中 -2147483646 - 2147483646 = 4,所以会发生交换,导致排序结果不正确,在后续判断气球是否重叠时也不正确
-2147483646 - 2147483646 = 4的解释:
由于int的值范围是[-2147483648, 2147483647] , 并且
-2147483648 - 1= 2147483647,
2147483647 + 1 = -2147483648,
相当于int值的最大和最小值是互通的,所以
-2147483646 - 2147483646 = 4
-> -2147483646 - 2 - 1 - 2147483643 = 4
-> -21474836468 - 1 - 2147483643 = 4
-> 2147483647 - 2147483643 = 4
解决方案一:
在lambda表达式中,用long类型进行运算,根据运算结果返回1,0或-1
//重写lambda表达式
Arrays.sort(points, (p1, p2)->{
long p1_num = (long) p1[0];
long p2_num = (long) p2[0];
if(p1_num - p2_num > 0) {
return 1;
}else if(p1_num == p2_num) {
return 0;
}else {
return -1;
}
});
解决方案二:
使用Integer.compare(int x, int y),比较逻辑是根据大于小于号比较的,不是根据差值比较,比较结果会返回1,0或-1
//lambda表达式
Arrays.sort(points, (o1, o2) -> Integer.compare(o1[0], o2[0]));
//查看Integer.compare(int x, int y)源码
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}