所用代码 java
柠檬水找零 LeetCode 860
题目链接:柠檬水找零 LeetCode 860 - 简单
思路
主要看收到的是几元的,需不需要找钱:
-
收到5元,直接收下
-
收到10元,收下,并找5元
-
收到20元,收下:
- 有10元的,先找一张10元,再找一张5元
- 没有10元的,直接找3张5元
class Solution {
public boolean lemonadeChange(int[] bills) {
// 数组下标0 1 2 分别表示 5 10 20 元
int[] money = new int[3];
for (int i = 0; i < bills.length; i++) {
// 5块直接收
if (bills[i] == 5) {
money[0]++;
}
// 10块找5块
else if (bills[i] == 10) {
money[1]++;
if (money[0] > 0){
money[0]--;
}else return false;
}
// 20先找一张10块一张五块,没有就找3张五块
else if (bills[i] == 20){
if (money[1] > 0 && money[0] > 0){
money[1]--;
money[0]--;
}else if (money[0] >= 3){
money[0] = money[0] - 3;
}else return false;
}
}
return true;
}
}
总结
这题贪心主要是要先找大的钱,就是说收到20要先找10+5,没有再找5+5+5,因为5元的更万能,既可以用来找零10元,也可以用来找零20元。
本题也可以用三个整型的数来表示 5元 10元 20 元,开销会更小 。
根据身高重建队列 LeetCode 406
题目链接:根据身高重建队列 LeetCode 406 - 中等
思路
无。
两步的贪心需仔细判断先走哪一步。
- 先逆序排序好h值,即身高,就保证了前面的身高都比自己高。
- 然后确定k值,即排序前面比自己高的人有多少。
若按身高值的顺序再确定k值,比较排序是否合理,若不合理则应该插入道前面去。
class Solution {
public int[][] reconstructQueue(int[][] people) {
// 按身高从大到小排序,排序小的在前
Arrays.sort(people, ((o1, o2) -> {
// 若第一个数(身高)相等,k值小的排在前
if (o1[0] == o2[0]) return o1[1]-o2[1];
// 否则按k值升序排序
return o2[0] - o1[0];
}));
// 每次按k值来插入并排序
LinkedList<int[]> que = new LinkedList<>();
for (int i = 0; i < people.length; i++) {
int postion = people[i][1];
// 在下标为postion的位置插入people[]
que.add(postion, people[i]);
}
// 链表转数组
return que.toArray(new int[people.length][]);
}
}
总结
本题和前面分发糖果的题类似,都是要进行两次操作。第一次贪的是身高,要先找升高高的排前面,若身高相等就按k值,第二贪的才是k值,在身高从大到小已经确定的情况下,再按k值插入。
注意: 有两个维度的题一定要先确定好一个维度,然后再按照另一个维度进行排序。
用最少数量的箭引爆气球 LeetCode 452
题目链接:用最少数量的箭引爆气球 LeetCode 452 - 中等
思路
先把每一个区间按起始位置排序,然后比较后一个的起始是不是在前一个区间里面。
class Solution {
public int findMinArrowShots(int[][] points) {
if (points == null || points.length == 0) return 0;
// 默认需要一只箭
int count = 1;
// 按气球x坐标的起始点排序
// Integer.compare可以排序 [[-2147483646,-2147483645],[2147483646,2147483647]]
Arrays.sort(points, (o1, o2) -> Integer.compare(o1[0],o2[0] ));
// for (int[] point : points) {
// System.out.println(Arrays.toString(point));
// }
// 从第二个区间开始,因为每次和前一个区间进行比较
for (int i = 1; i < points.length; i++) {
// 左边界大于右边界,就需要多一只箭
if (points[i][0] > points[i-1][1]){
count++;
}else { // 区间有重叠的情况,就更新右边界,边界应取最小值
points[i][1] = Math.min(points[i][1], points[i-1][1]);
}
}
return count;
}
}
总结
按我自己的方法(cur指针和pre指针)只考虑右边界大于了左边界,就换下一个区间比较的话会漏掉处于中间的区间。比如:[1, 8], [2, 3], [4, 5], [9,10] 这几个区间我的方法会漏掉中间的小区间。
所以更新的时候要以小的右边界的边界点。
注意错误!!!!
- int型 -2147483645 和 214748364 比较
- 漏掉小区间
class Solution {
public int findMinArrowShots(int[][] points) {
// 默认需要一只箭
int count = 1;
// 按气球x坐标的起始点排序
第一个错误:没用integer的包装类区间比较会出错[[-2147483646,-2147483645],[2147483646,2147483647]]
Arrays.sort(points, (o1, o2) -> o1[0]-o2[0]);
第二个错误:漏掉小区间!!!
// pre指向前一个区间
int pre = 0;
// cur指向目前区间
int cur = 1;
while (cur < points.length){
if (points[pre][1] >= points[cur][0]){
// cur指针往后移一位,比较下一个区间的起点
cur++;
continue;
}else {
pre = cur;
cur++;
count++;
}
}
return count;
}
}