【代码训练营】day 34 | 860.柠檬水找零 & 406.根据身高重建队列 & 452. 用最少数量的箭引爆气球

文章讲述了使用Java解决LeetCode中的找零问题,强调了贪心算法的应用,如优先找大面额的零钱,以及在处理不同金额时的策略。同时提到了其他两道中等难度的LeetCode题目,分别是根据身高重建队列和用最少数量的箭引爆气球,同样涉及到排序和优化策略。
摘要由CSDN通过智能技术生成

所用代码 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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值