算法通关第十七关白银挑战——贪心算法的高频算法题

大家好,我是怒码少年小码。

今天早上起来的时候发现我的一篇公众号的文章火了!超级开心!原来这就是有流量支持的底气嘛~

书接上文,本篇主要讲解贪心思想的几个经典例题。

区间问题

判断区间是否重叠

LeetCode 252:给定一个会议时间安排的数组 intervals ,每个会议时间都会包括开始和结束的时间 intervals[i] = [starti, endi] ,请你判断一个人是否能够参加这里面的全部会议。

示例:

  • 输入:intervals = [[0,30],[15,20],[5,10]]
  • 解释:存在重叠区间,一个人在同一时刻只能参加一个会议。

作图:

分析:这题判断区间是否重合,用人话来说就是判断你正在参加的这个会议还没结束,你是否又需要去开另一个会议?也就是将会议区间按开始时间排好之后,当前会议的结束时间是否大于下一个会议的开始时间

  • 如果是。那么你这个会还没结束又要去参加别的,存在重叠区间。
  • 如果不是。不存在重叠区间。

代码实现:

public boolean canAttendMeetings(int[][] intervals) {
  // 将区间按照会议开始实现升序排序
  Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
  // 遍历会议,如果下一个会议在前一个会议结束之前就开始了,返回 false。
  for (int i = 1; i < intervals.length; i++) {
      if (intervals[i][0] < intervals[i - 1][1]) {
          return false;
      }
  }
  return true;
}

合并区间

LeetCode 56:以数组intervals表示若干个区间的集合,其中单个区间为intervals[i] = [starti, endi]。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

示例:

  • 输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
  • 输出:[[1,6],[8,10],[15,18]]
  • 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

作图:

分析:很显然这题首先也是要找出重叠的区间,方法和上面一题一样:先按起始位置排序,然后从第二个区间开始,比较当前区间的起始位置和上一个区间的结束位置。

  • 重叠,就合并。观察上图,合并的本质就是当前区间的起始位置和上一个区间的结束位置取最大值。合并后装入一个结果数组中。
  • 不重叠。直接放到结果数组中。

代码实现:

public int[][] merge(int[][] intervals) {
  //按起始位置排序
  Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
  //新的结果返回数组
  int[][] res = new int[intervals.length][2];
  int idx = -1 ;
  for(int[] interval :intervals){
  // 如果结果数组是空的,或者当前区间的起始位置 > 结果数组中最后区间(上一个区间)的终止位置,
  // 则两个区间不重叠,不用合并,直接将当前区间加入结果数组。
    if(idx == -1 || interval[0] > res[idx][1]){
        res[++idx]=interval;
    }else{
        //合并的本质就是把两个区间的结束位置取一个最大值
        res[idx][1] = Math.max(res[idx][1],interval[1]);
    }
  }
  return Arrays.copyOf(res,idx + 1);
}

插入区间

LeetCode 57:给你一个无重叠的,按照区间起始端点排序的区间列表。在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。

示例 1:

  • 输入:intervals = [[1,3],[6,9]], newInterval = [2,5]
  • 输出:[[1,5],[6,9]]

示例 2:

  • 输入:intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
  • 输出:[[1,2],[3,10],[12,16]]
  • 解释:这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠。

作图:

分析:本题就是上一题的再拓展,本题中的区间已经按照起始端点升序排列,因此我们直接遍历区间列表,寻找新区间的插入位置即可。具体步骤如下:

  • 首先将新区间左边且相离的区间加入结果集(遍历时,如果当前区间的结束位置小于新区间的开始位置,说明当前区间在新区间的左边且相离)
  • 接着判断当前区间是否与新区间重叠,重叠的话就进行合并,直到遍历到当前区间在新区间的右边且相离,将最终合并后的新区间加入结果集;
  • 最后将新区间右边且相离的区间加入结果集。

相当于把原数组分成两个部分:比新区间小的且不重合的、重合的、比新区大的且不重合的

代码实现:

public int[][] insert(int[][] intervals, int[] newInterval) {
    int[][] res = new int[intervals.length + 1][2];
    int idx = 0;
    // 遍历区间列表:
    // 首先将新区间左边且相离的区间加入结果集
    int i = 0;
    while (i < intervals.length && intervals[i][1] < newInterval[0]) {
        res[idx++] = intervals[i++];
    }
    // 判断当前区间是否与新区间重叠,重叠的话就进行合并,直到遍历到当前区间在新区间的右边且相离,
    // 将最终合并后的新区间加入结果集
    while (i < intervals.length && intervals[i][0] <= newInterval[1]) {
        newInterval[0] = Math.min(intervals[i][0], newInterval[0]);
        newInterval[1] = Math.max(intervals[i][1], newInterval[1]);
        i++;
    }
    res[idx++] = newInterval;
    // 最后将新区间右边且相离的区间加入结果集
    while (i < intervals.length) {
        res[idx++] = intervals[i++];
    }
    return Arrays.copyOf(res, idx);
}

字符串分割

LeetCode 736:字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。

示例 1:

  • 输入:s = “ababcbacadefegdehijhklij”
  • 输出:[9,7,8]
  • 解释:划分结果为 “ababcbaca”、“defegde”、“hijhklij” 。
    每个字母最多出现在一个片段中。 像 “ababcbacadefegde”, “hijhklij” 这样的划分是错误的,因为划分的片>- 段数较少。

示例 2:

  • 输入:s = “eccbbbbdec”
  • 输出:[10]

分析:如何把同一个字母的都圈在同一个区间里呢?该遍历过程相当要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。所以可以这么做:

  • 首先,统计每一个字符最后出现的位置
  • 然后,从头遍历字符,并更新字符的最远出现下标,如果找到字符最远出现位置下标和当前下标相等了,则找到了分割点。

代码实现:

public List<Integer> partitionLabels(String s) {
    //结果数组,用于保存每个子串的长度
    List<Integer> list = new ArrayList<>();
    //用于保存每个字符在字符串中最后一次出现的索引
    int[] edge = new int[26];
    char[] chars = s.toCharArray(); //将字符串s转换为字符数组chars。
    for(int i = 0 ;i < chars.length;i++){
        edge[chars[i] - 'a'] = i;  
    }
    int idx = 0; //当前已经遍历过的字符中最大的索引
    int last = -1; //上一个子串的结束索引
    for(int i = 0; i < chars.length; i++){
        idx = Math.max(idx,edge[chars[i] - 'a']);
        if(i == idx){
            list.add(i-last);
            last = i;
        }
    }
    return list;
}

edge[chars[i] - 'a'] = i;是用来更新数组edge中每个字符的最后出现位置索引。

初始化两个变量idx和last,分别表示当前已经遍历过的字符中最大的索引和上一个子串的结束索引。初始时,last的值为-1,表示还没有开始枚举子串。

再次遍历字符数组chars,对于每个字符的索引i,更新idx为idx和edge[chars[i] - ‘a’]中的较大值。这样,idx表示当前已经遍历过的字符中最大的索引(即最远的字符)。

如果当前字符的索引i等于idx,说明当前字符是一个独立的子串,因为它是从上一个子串后面的第一个出现的。此时,将当前子串的长度i - last添加到列表list中,并将last更新为当前索引i,以便开始下一个子串的计算。遍历完成后,列表list中保存了每个子串的长度,将其作为结果返回。

加油站问题

LeetCode 134:在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。

示例 :

  • 输入: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
  • 输出: 3
  • 解释:
    从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
    开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油
    开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油
    开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油
    开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油
    开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。
    因此,3 可为起始索引。

分析:什么时候能汽车跑?只有gas[i] - cost[i] >= 0的时候才能开始跑,这样i才能作为开始位置。

再思考:汽车什么情况下能一直跑?例如从位置i跑到位置i+4,是不是油量curSum有所剩余才能跑?如果跑到i+3,curSum < 0无法跑完全程,说明开始位置选取的不对,i到i+3都无法作为开始位置,需要更新开始位置。

特殊情况:如果全程的总油量减去总消耗小于零,则无论从哪里开始都跑不完全程

代码实现:

public int canCompleteCircuit(int[] gas, int[] cost) {
    int curSum = 0; 
    int totalSum = 0;//总油量
    int start = 0;
    for(int i = 0 ; i < gas.length;i++){
        curSum += gas[i] - cost[i];
        totalSum += gas[i] - cost[i];
        if(curSum < 0){
            start = i + 1; //更新汽车开始的位置
            curSum = 0 ;//归零curSum。重新开始算
        }
    }
    if(totalSum < 0) return -1; //说明从哪里开始开车都不行
    return start;
}

END

相信如果你完全做完这些题会有一种酣畅淋漓的感觉😎,下一篇会是贪心关于跳跃的问题的详解。今天早上的时候我的公众号迎来了第一批涨粉,这一天的心情都好了。

关注微信公众号:怒码少年。回复关键词【电子书】,领取多本计算机相关电子书

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/196130.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode—15.三数之和【中等】

2023每日刷题&#xff08;四十一&#xff09; Leetcode—15.三数之和 实现代码 class Solution { public:vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(), nums.end());vector<vector<int>> ans;int i, j, k;int s,…

移植NXP官方uboot到IMX6ULL开发板--以及过程中遇到的疑问和错误记录

目录 1 下载uboot源码 2在uboot中添加自己的开发板 2.1 添加开发板默认配置文件 疑问&#xff1a;defconfig文件里面为什么没有CONFIG_SYS_EXTRA_OPTIONS"IMX_CONFIGboard/freescale/mx6ullevk/imximage.cfg,MX6ULL_EVK_EMMC_REWORK" 2.2 添加开发板对应的头文…

k8s中pod的hostport端口突然无法访问故障处理

故障背景&#xff1a; 租户告知生产环境的sftp突然无法访问了&#xff0c;登录环境查看sftp服务运行都是正常的&#xff0c;访问sftp的hostport端口确实不通。 故障处理过程 既然访问不通那就先给服务做个全面检查&#xff0c;看看哪里出了问题&#xff0c;看下sftp日志&#…

VIR-SLAM代码分析2——VIR_VINS详解

前言 VIR-SLAM中VIR_VINS文件夹下是基于VINS-mono的结合UWB传感器的估计器&#xff0c;主要改动的文件在uwb_posegraph&#xff0c;vir_estimator中。其他文件夹完成的是UWB数据的处理问题&#xff0c;比较简单上一节介绍足够&#xff0c;代码也容易看懂。本节介绍的VIR_VINS是…

软件测试简历编写技巧,对症下药,一周面10家...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 作为HR来说&#…

吉利银河L6 纯电模式 空调加热功率

环境 环境10摄氏度左右 空调加热最高档 风速最高档 慢充充电 地下车库 开空调充电 关空调充电 分析 充电功率6kw 开关空调时间差了一倍 所以估算出空调加热峰值功率大概3kw左右

aPEAR包绘制功能富集网络图

本期教程 前言 今天学习aPEAR包&#xff0c;绘制KEGG和GO功能富集网络图&#xff0c;用起来还是比较方便的&#xff0c;直接将clusterProfiler富集结果进行绘制&#xff0c;对人类、动物等分析结果非常方便。对于模式植物&#xff0c;使用自己制作的GO或KEGG背景文件进行富集分…

UI上传组件异步上传更改为同步

实现异步方法 JavaScript 异步 实现异步的五种实现方法_js异步-CSDN博客 这两种比较经常用。 因为上传组件是异步上传的通过Async和await配合使用可以上传完照片视频后返回的地址在继续走下去&#xff0c;而不是图片视频地址还未获取时就上传后端了。

Notion for Mac:打造您的专属多功能办公笔记软件

在如今这个信息爆炸的时代&#xff0c;一款高效、便捷的笔记软件对于办公人士来说已经成为必不可少的工具。Notion for Mac&#xff0c;作为一款多功能办公笔记软件&#xff0c;凭借其简洁优雅的界面、强大的功能以及无缝的云端同步&#xff0c;成为了众多用户的首选。 一、多…

9.二维数组——打印出杨辉三角形(要求打印出10行)

文章目录 前言一、题目描述 二、题目分析 三、解题 程序运行代码 前言 本系列为二维数组编程题&#xff0c;点滴成长&#xff0c;一起逆袭。 一、题目描述 打印出杨辉三角形&#xff08;要求打印出10行&#xff09;。 二、题目分析 三、解题 程序运行代码 #include<s…

python实现rpc的几种方式(SimpleXMLRPCServer 自带的、第三方ZeroRPC)、连接linux远程开发分布式锁、分布式id

1 python实现rpc的几种方式 1.1 SimpleXMLRPCServer 自带的 1.2 第三方ZeroRPC 2 连接linux远程开发 3 分布式锁 4 分布式id 1 python实现rpc的几种方式 # 远程过程调用-1 借助于rabbitmq,可以跨语言-2 SimpleXMLRPCServer 自带的-3 ZeroRPC-4 GRPC&#xff1a;跨语言的 htt…

GAN:ImprovedGAN-训练GAN的改进策略

论文&#xff1a;https://arxiv.org/abs/1606.03498 代码&#xff1a;https://github.com/openai/improved_gan 发表&#xff1a;NIPS 2016 一、文章创新 1&#xff1a;Feature matching&#xff1a;特征匹配通过为生成器指定新目标来解决GANs的不稳定性&#xff0c;从而防止…

富富集网络图绘制教程

本期教程 前言 今天学习aPEAR包&#xff0c;绘制KEGG和GO功能富集网络图&#xff0c;用起来还是比较方便的&#xff0c;直接将clusterProfiler富集结果进行绘制&#xff0c;对人类、动物等分析结果非常方便。对于模式植物&#xff0c;使用自己制作的GO或KEGG背景文件进行富集分…

Python能否成为大型游戏开发的利器?

你是否曾想过&#xff0c;Python这个备受欢迎的编程语言是否能够胜任大型游戏开发的重任&#xff1f;Python以其简洁、易学的特点而著称&#xff0c;但在游戏世界中&#xff0c;性能和效率常常是关键。小编将带你深入探讨Python在大型游戏开发中的潜力&#xff0c;一探究竟&…

【Unity细节】为什么加载精灵图集直接导致Unity引擎崩溃

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 &#x1f636;‍&#x1f32b;️收录于专栏&#xff1a;unity细节和bug &#x1f636;‍&#x1f32b;️优质专栏 ⭐【…

立即修复计算机显示msvcp110.dll丢失问题!4个快速解决方法大揭秘

在计算机使用过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“msvcp110.dll丢失”。这个错误通常会导致某些程序无法正常运行&#xff0c;给用户带来诸多不便。那么&#xff0c;当我们遇到这个问题时&#xff0c;应该如何进行修复呢&#xff1f;本文将…

数据仓库建模下篇

在实际业务中&#xff0c;给了我们一堆数据&#xff0c;我们怎么拿这些数据进行数仓建设呢&#xff0c;数仓工具箱作者根据自身多年的实际业务经验&#xff0c;给我们总结了如下四步。 数仓工具箱中的维度建模四步走&#xff1a; 维度建模四步走 这四步是环环相扣&#xff0c…

latex中$$中的字母不显示斜体【已解决】

最近在用latex写论文&#xff0c;其中一篇论文的方法名带有平方&#xff0c;但是当我写方法名的时候发现字母名称是斜体的&#xff0c;如下图所示 引用的论文中FedME这几个字显然不是斜体&#xff0c;最后修改完的图片如下图所示 代码如下所示 /非斜体代码 $\text{FedME}^{2}$…

怎么把dwg格式转换pdf?

怎么把dwg格式转换pdf&#xff1f;DWG是一种由AutoCAD开发的二维和三维计算机辅助设计&#xff08;CAD&#xff09;文件格式&#xff0c;它的名称是“绘图&#xff08;Drawing&#xff09;”的缩写。DWG文件通常包含了设计图纸、模型和元数据等信息&#xff0c;并且被广泛用于工…

利用STM32和蓝牙模块构建智能物联网设备的开发指南

智能物联网设备在现代生活中扮演着重要的角色&#xff0c;而STM32微控制器和蓝牙模块则为实现智能物联网设备提供了基础支持。本文将介绍如何使用STM32微控制器和蓝牙模块构建智能物联网设备的开发指南&#xff0c;包括硬件设计、蓝牙模块配置、传感器数据采集和云平台连接等关…