算法学习day29-贪心算法

加油站

核心思路

  • 思路1, 全局

    • 如果能跑完全程, 那么加油站的油的总和一定是大于cost的总和的

    • 能跑完全程的前提下, 找到欠油的min, 从后往前执行, 找到能把min填平的下标, 就是起点

    • 这个逻辑还是有点难理解, 二刷的时候再捋一下吧

      java 复制代码
      public int canCompleteCircuit(int[] gas, int[] cost) {
          int curLast = 0;
          int min = 0;
          for (int i = 0; i < gas.length; i++) {
              curLast += gas[i] - cost[i];
              min = Math.min(min, curLast);
          }
          //说明加油站的油不足以支撑跑完全程
          if(curLast < 0){
              return -1;
          }
          //说明从0出发就能够跑完全程
          if(min >= 0){
              return 0;
          }
          //倒着执行, min说明这条路从0到结束最多欠了多少油
          //从后往前执行, 找到能填满min的位置, 就是起始位
          for (int i = gas.length - 1; i >= 0 ; i--) {
              min += gas[i] - cost[i];
              if(min >= 0){
                  return i;
              }
          }
          return -1;
      }
  • 思路2, 贪心

    • 首先确保 加油站的油的总和一定是大于cost的总和

    • 在这个前提下, 从0出发, 计算每个下标的剩余油量, 如果出现 负的, 那么就从i+1重新出发

    • 那么最终的结果, 要么totalCost<0, return -1

    • 要么出现一个index, 能够跑完全程

      java 复制代码
      public int canCompleteCircuit(int[] gas, int[] cost) {
          int totalCost = 0;
          int curLast = 0;
          int beginIndex = 0;
          for (int i = 0; i < gas.length; i++) {
              curLast += gas[i] - cost[i];
              totalCost += gas[i] - cost[i];
              if (curLast < 0) {
                  curLast = 0;
                  beginIndex = (i + 1) % gas.length;
              }
          }
          if(totalCost < 0){
              return -1;
          }
          return beginIndex;
      }

分发糖果

核心思路

  • 分成两次循环, 分别判断大于左孩子和大于右孩子

  • 需要注意的是, 判断左孩子, 要从前向后, 因为每次计算糖果的时候, 都要用到左孩子的值, 如果从后向前, 左孩子的值还没有更新

  • 右孩子同理, 要从后向前

    java 复制代码
    public int candy(int[] ratings) {
        int[] candy = new int[ratings.length];
        Arrays.fill(candy, 1);
        for (int i = 1; i < ratings.length; i++) {
            if (ratings[i] > ratings[i - 1]) {
                candy[i] = Math.max(candy[i - 1] + 1, candy[i]);
            }
        }
        for (int i = ratings.length - 2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1]) {
                candy[i] = Math.max(candy[i + 1] + 1, candy[i]);
            }
        }
        return IntStream.of(candy).sum();
    }

卖柠檬水

  • 这道题就单纯的考思路了

    • 5元的不用处理,

    • 10元的只能找5元的, 所以ten++, five--

    • 20元的, 既可以ten--,five--. 也可以five-=3

      • 那么这时候就要贪心一下, 优先ten--, 因为10元只能用于找零20块的, 所以尽可能的消耗10元
      java 复制代码
      public boolean lemonadeChange(int[] bills) {
          int five = 0;
          int ten = 0;
          for (int bill : bills) {
              if (bill == 5) {
                  five++;
              } else if (bill == 10) {
                  ten++;
                  five--;
              } else {
                  if (ten > 0) {
                      ten--;
                      five--;
                  } else {
                      five -= 3;
                  }
              }
              if (five < 0) {
                  return false;
              }
          }
          return true;
      }

根据身高重建队列

核心思路

  • 当有多个维度的时候, 要考虑能不能一个维度一个维度的分开处理

  • 这道题有两个维度, 一个是身高h, 一个是顺序k

    • 如果先根据k排序, 那么h会影响到k的排序效果, 所以先处理k不行
    • 如果先根据身高排序
      • 先处理高个子之后, 矮个子无论插入到哪个位置, 都不会影响到高个子的相对位置
      • 高个子看不见矮个子
    • 根据身高排序之后
      • 再顺序遍历, 将person[i] 插入到list的person[i][1]中, 就会发现
      • 由于先插入的是高个子, 矮个子即使插入到高个子前面, 也不会影响到高个子的相对位置!
    java 复制代码
    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];
        });
        ArrayList<int[]> list = new ArrayList<>();
        for (int[] person : people) {
            list.add(person[1], person);
        }
        return list.toArray(new int[people.length][]);
    }
相关推荐
橘颂TA2 小时前
【剑斩OFFER】算法的暴力美学——力扣 1765 题:地图中的最高点
算法·leetcode·职场和发展·结构与算法
Full Stack Developme2 小时前
算法与数据结构,到底是怎么节省时间和空间的
数据结构·算法
棱镜Coding2 小时前
LeetCode-Hot100 28.两数相加
算法·leetcode·职场和发展
m0_561359672 小时前
C++中的过滤器模式
开发语言·c++·算法
HL_风神2 小时前
QT事件循环机制源码学习
开发语言·qt·学习
AI科技星2 小时前
加速运动电荷产生引力场方程求导验证
服务器·人工智能·线性代数·算法·矩阵
啊阿狸不会拉杆2 小时前
《数字信号处理》第9章:序列的抽取与插值——多抽样率数字信号处理基础
算法·matlab·信号处理·数字信号处理·dsp
what丶k2 小时前
深入理解贪心算法:从原理到经典实践
算法·贪心算法·代理模式
郝学胜-神的一滴2 小时前
B站:从二次元到AI创新孵化器的华丽转身 | Google Cloud峰会见闻
开发语言·人工智能·算法