贪心算法part3

贪心算法part3

134. 加油站 - 力扣(LeetCode)

总体思路:

  1. 如果gas[i]总和 > cost[i]总和, 不可能跑完, 直接返回-1
  2. 贪心: 新增一个rest数组, 计算当前的gas[i] - cost[i]总和, 如果总和小于0, 那么更新答案下标为i + 1
    • 局部最优: 当前累加rest[i]的和curSum一旦小于0,起始位置至少要是i+1,因为从i之前开始一定不行。
    • 全局最优:找到可以跑一圈的起始位置。

代码:

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int[] rest = new int[gas.length];
        int curSum = 0;
        int res = 0;
        for(int i = 0; i < rest.length; i++){
            curSum += gas[i];
            curSum -= cost[i];
        }
        if(curSum < 0){
            return -1;
        }
        curSum = 0;
        for(int i = 0; i < rest.length; i++){
            rest[i] = gas[i] - cost[i];
            curSum += rest[i];
            if(curSum < 0){
                res = i + 1;
                curSum = 0;
            }
        }
        return res;
    }
}

135. 分发糖果 - 力扣(LeetCode)

难度为困难

这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼

贪心策略:

  • 一次是从左到右遍历,只比较右边孩子评分比左边大的情况
  • 一次是从右到左遍历,只比较左边孩子评分比右边大的情况

代码如下:

class Solution {
    public int candy(int[] ratings) {
        int[] candies = new int[ratings.length];
        Arrays.fill(candies, 1);
        for(int i = 1; i < ratings.length; i++){
            if(ratings[i] > ratings[i - 1]){
                candies[i] = candies[i - 1] + 1;
            }
        }
        for(int i = ratings.length - 1; i > 0; i--){
            if(ratings[i - 1] > ratings[i]){
                candies[i - 1] = candies[i - 1] > candies[i] + 1 ? candies[i - 1] : candies[i] + 1; //这里是特殊情况,局部贪心,如果当前节点是山峰,要确保当前节点改动之后还是山峰
            }
        }
        int res = 0;
        for(int i = 0; i < candies.length; i++){
            res += candies[i];
        }
        return res;
    }
}

tips:

数组填充函数:

Arrays.fill(array[], int)

860. 柠檬水找零 - 力扣(LeetCode)

唯一贪心的体现:收取20时,优先用10支付,没啥意思这题

class Solution {
    public boolean lemonadeChange(int[] bills) {
        HashMap<Integer, Integer> record = new HashMap<>();
        record.put(5, 0);
        record.put(10, 0);
        for(int i = 0; i < bills.length; i++){
            if(bills[i] == 5){
                record.put(5, record.get(5) + 1);
            }else if(bills[i] == 10){
                int num = record.get(5);
                if(num < 1){
                    return false;
                }
                record.put(5, num - 1);
                record.put(10, record.get(10) + 1);
            }else{
                int num5 = record.get(5);
                int num10 = record.get(10);
                if(num5 < 1){
                    return false;
                }else if(num5 <= 2 && num10 < 1){
                    return false;
                }else if(num10 > 0){
                    record.put(10, num10 - 1);
                    record.put(5, num5 - 1);
                }else {
                    record.put(5, num5 - 3);
                }
            }
        }
        return true;
    }
}

406. 根据身高重建队列 - 力扣(LeetCode)

本题要从两个维度考虑排序,一个是身高维度,另一个是根据身高排序

为什么要先从身高考虑,进行第一次排序?

  • 因为先将身高从大到小排序之后,再根据身高进行排序,那么小身高无论放在大身高的前还是后,都不会对大身高造成影响,最后得到的队列一定没问题

此题思路很好理解,但是Java的语法不太好写,需要排序器学的很好

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];  //身高按降序排列
        });
        LinkedList<int[]> res = new LinkedList<>();  //使用linkedList进行结果的构建,队列
        for(int[] arr : people){
            res.add(arr[1], arr);  // arr[1]是插入的位置, arr是要插入的数组
        }
        return res.toArray(new int[people.length][]);
    }
}
posted @ 2025-06-24 20:31  泡芙猪  阅读(33)  评论(0)    收藏  举报