代码随想录Day34|贪心算法|134. 加油站、135. 分发糖果、860.柠檬水找零、406.根据身高重建队列


代码随想录开源LeetCode题单:代码随想录


1.LeetCode134

LeetCode134. 加油站

1.1 思路

  • 核心思路:
    • 总油量 vs. 总消耗:
      • 如果总油量 sum(gas) >= sum(cost),则一定可以绕一圈。
      • 如果总油量 sum(gas) < sum(cost),则无法绕一圈,直接返回 -1。
    • 当前油量判断起点:
      • 遍历过程中,维护一个变量 curr_tank,表示当前油量。
      • 如果当前油量小于 0,说明从当前起点无法到达下一站,则需要重新选择起点,并重置当前油量。
  • 贪心策略:
    每次遇到油量不足的情况,更新起点为下一站,因为前面无法到达的加油站都不可能是有效起点。

1.2 代码

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int sum = 0;
        int min = 0;
        for (int i = 0; i < gas.length; i++) {
            sum += (gas[i] - cost[i]);
            min = Math.min(sum, min);
        }

        if (sum < 0) return -1;
        if (min >= 0) return 0;

        for (int i = gas.length - 1; i > 0; i--) {
            min += (gas[i] - cost[i]);
            if (min >= 0) return i;
        }

        return -1;
    }
}

2.LeetCode135

LeetCode135. 分发糖果

2.1思路

双数组贪心法

  • 核心问题:
    • 满足条件:
      • 每个孩子至少有 1 个糖果。
      • 评分高的孩子比相邻评分低的孩子分得更多的糖果。
    • 目标:
      • 最小化糖果的总数。
  • 贪心策略:
    • 从左到右遍历数组:
      • 如果当前孩子评分比左边高,则糖果数比左边多 1。
    • 从右到左遍历数组:
      • 如果当前孩子评分比右边高,则糖果数比右边多 1。
    • 最终结果为两次遍历中每个孩子的最大糖果数。
  • 步骤分析:
    初始化两个数组 left 和 right,分别记录从左到右和从右到左遍历时的糖果分配情况,初始值均为 1。
    • 第一次遍历:
      从左到右遍历 ratings,如果当前评分比左边评分高,更新 left[i] = left[i-1] + 1。
    • 第二次遍历:
      从右到左遍历 ratings,如果当前评分比右边评分高,更新 right[i] = right[i+1] + 1。
    • 计算结果:
      对于每个孩子,糖果数取 max(left[i], right[i])。

2.2 代码

class Solution {
    /**
         分两个阶段
         1、起点下标1 从左往右,只要 右边 比 左边 大,右边的糖果=左边 + 1
         2、起点下标 ratings.length - 2 从右往左, 只要左边 比 右边 大,此时 左边的糖果应该 取本身的糖果数(符合比它左边大) 和 右边糖果数 + 1 二者的最大值,这样才符合 它比它左边的大,也比它右边大
    */
    public int candy(int[] ratings) {
        int len = ratings.length;
        int[] candyVec = new int[len];
        candyVec[0] = 1;
        for (int i = 1; i < len; i++) {
            candyVec[i] = (ratings[i] > ratings[i - 1]) ? candyVec[i - 1] + 1 : 1;
        }

        for (int i = len - 2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1]) {
                candyVec[i] = Math.max(candyVec[i], candyVec[i + 1] + 1);
            }
        }

        int ans = 0;
        for (int num : candyVec) {
            ans += num;
        }
        return ans;
    }
}

3.LeetCode860

LeetCode860.柠檬水找零

3.1 思路

  • 核心思想:

    • 每次优先使用大面额的零钱找零(如优先使用 $10 钞票找零),以便留更多的小额零钱($5 钞票)用于后续找零。
    • 模拟找零过程,判断是否能满足所有顾客的找零需求。
  • 详细步骤:

    • 初始化两个变量 five 和 ten 分别记录当前持有的 $5 和 $10 钞票数量。
    • 遍历每一位顾客的付款金额:
      • 如果顾客付 $5:无需找零,仅记录收到的 $5 钞票。
      • 如果顾客付 $10:找零 $5。如果没有 $5 钞票,返回 False;否则,减少 $5 钞票数量,增加 $10 钞票数量。
      • 如果顾客付 $20:优先使用 $10 和 $5 找零(找零 $15)。如果没有 $10,则使用三个 $5 钞票。如果无法找零,返回 False。
    • 如果遍历完毕都能找零,返回 True。

3.2 代码

class Solution {
    public boolean lemonadeChange(int[] bills) {
        int five = 0;
        int ten = 0;

        for (int i = 0; i < bills.length; i++) {
            if (bills[i] == 5) {
                five++;
            } else if (bills[i] == 10) {
                five--;
                ten++;
            } else if (bills[i] == 20) {
                if (ten > 0) {
                    ten--;
                    five--;
                } else {
                    five -= 3;
                }
            }
            if (five < 0 || ten < 0) return false;
        }
        
        return true;
    }
}

4.LeetCode406

LeetCode406.根据身高重建队列

4.1 思路

  • 排序规则:

    • 按照身高从高到低排序,若身高相同,则按照 k 值从小到大排序:
      • 身高高的人先放入队列,确保不会影响后续身高较矮的人的 k 值计算。
      • 身高相同时,k 值小的人优先放入,确保队列结构正确。
  • 队列插入:

    • 按排序后的顺序依次将每个人插入队列:
      • 根据每个人的 k 值,将其插入结果队列的对应位置。
  • 为什么贪心有效:

    • 身高高的人优先放置,确保后续插入时不会影响较矮的人的 k 值计算。
    • 插入操作基于当前的 k 值,直接反映每个人的要求

4.2 代码

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        // 身高从大到小排(身高相同k小的站前面)
        Arrays.sort(people, (a, b) -> {
            if (a[0] == b[0]) return a[1] - b[1];   // a - b 是升序排列,故在a[0] == b[0]的狀況下,會根據k值升序排列
            return b[0] - a[0];   //b - a 是降序排列,在a[0] != b[0],的狀況會根據h值降序排列
        });

        LinkedList<int[]> que = new LinkedList<>();

        for (int[] p : people) {
            que.add(p[1],p);   //Linkedlist.add(index, value),會將value插入到指定index裡。
        }

        return que.toArray(new int[people.length][]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值