代码随想录算法训练营day35 || 860.柠檬水找零,406. 根据身高重建队列,452. 用最少数量的箭引爆气球

视频讲解:

贪心算法,看上去复杂,其实逻辑都是固定的!LeetCode:860.柠檬水找零_哔哩哔哩_bilibili

贪心算法,不要两边一起贪,会顾此失彼 | LeetCode:406.根据身高重建队列_哔哩哔哩_bilibili

贪心算法,判断重叠区间问题 | LeetCode:452.用最少数量的箭引爆气球_哔哩哔哩_bilibili

860.柠檬水找零

思路:没有特别明确的贪心思想,可能涉及到贪心的思想就是在处理找零15元时,优先消耗10元的纸币,没有10元的,但消耗3张5元的。本题的关键就是统计5元,10元纸币的数量,虽然是有必要统计一下总共的利润来评估是否还有钱来找零,但是所有的找零都是花费的5元和10元,所以20元的无需统计,那么总利润统计也就没有意义,只要剩余的5元和10元纸币的数量可以应付所有找零,那么本题就可以返回true;反之返回一个false。

// 时间复杂度O(n)
// 空间复杂度O(1)

class Solution {
    public boolean lemonadeChange(int[] bills) {
        // 思路和昨天的加油站的第二种解法非常的类似
        // 分别用于计数5元,10元,20元
        int five = 0;
        int ten = 0;

        for(int i=0; i0)
                five--;
            else if(change==15 && ten>0 && five>0){
                // 找零15的时候应当优先消耗10元,这就是贪心的一部分
                five--;
                ten--;
            }
            else if(change == 15 && five>=3)
                five -= 3;
            else
                return false;
        }

        return true;
    }
}

406. 根据身高重建队列

思路:参考 代码随想录 的思路解出。明确涉及两个维度需要控制的题目时,优先确定一个维度然后再去操作另一个维度,即优先将一个维度的关系确定,然后再此基础上再去确定另一个维度。与此相同思路的题目中分发糖果,参考的左右两个相邻的位置,因此也是两个维度。

// 时间复杂度O(nlogn),是Arrays.sort()的时间复杂度
// 空间复杂度O(n)

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people, (a,b)->{
            if(a[0] == b[0])    return a[1]-b[1];
            return b[0]-a[0];
        });

        List que = new ArrayList<>();
        // 现在完成排序的people数组是h按照从大到小,k在h相同时才会使用到作为从小到大,用来维护之后进行赋值时的索引正确性
        // 而可以直接插入的缘故就是,将一个小的数加入到他的前面去不影响之前的数的h和k,因为之前的数的h都比当前数的h来的大
        
        for(int[] p:people)
            que.add(p[1], p);
        
        return que.toArray(new int[people.length][]);
    }
}

452. 用最少数量的箭引爆气球

思路:新的一种类型的题目——“重叠区间”。首先自己实现了这道题的题解,认为重叠区间类型题目的解题就是合并存在交集的区间,然后统计最终还剩下几个相互独立的区间;而贪心的策略就是如果可以时间效率最小的情况下完成区间的合并。在这个思路和两个维度的确定一个维度比较像,优先确定所有区间的下限的关系,然后再判断区间彼此之间是否存在交集,存在交集即融合即可。

// 时间复杂度O(nlogn),排序耗时
// 空间复杂度O(n)

class Solution {
    public int findMinArrowShots(int[][] points) {
        // 尝试先做,思路是计算重合的区间个数
        if(points.length == 1)
            return 1;
        // 按照起始的位置从小到大排列,注意这里需要自己写大小判断,然后返回负数还是正数,因为采用a[0]-b[0]的方式会存在数值越界的情况
        Arrays.sort(points, (a,b)->{
            if(a[0] < b[0]) return -1;
            if(a[0] == b[0]) return 0;
            return 1;
        });

        List scopes = new ArrayList<>();
        int[] cur = points[0];
        scopes.add(points[0]);
        
        // cur保存当前区间下限最小的,开始进行区间的合并
        for(int i=1; i (long)cur[1] ){
                scopes.add(points[i]);
                cur = points[i];
            }
            else{
                cur[0] = Math.max(cur[0], points[i][0]);
                cur[1] = Math.min(cur[1], points[i][1]);
            }
        }

        return scopes.size();

    }
}

你可能感兴趣的:(算法,java,leetcode)