代码随想录训练营 Day30打卡 贪心算法 part04 452. 用最少数量的箭引爆气球 435. 无重叠区间 763. 划分字母区间

news2025/1/9 5:54:36

代码随想录训练营 Day30打卡 贪心算法 part04

一、 力扣452. 用最少数量的箭引爆气球

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。
一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。
给你一个数组 points ,返回引爆所有气球所必须射出的 最小 弓箭数 。
示例
输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:气球可以用2支箭来爆破:
-在x = 6处射出箭,击破气球[2,8]和[1,6]。
-在x = 11处发射箭,击破气球[10,16]和[7,12]。

局部最优:当气球出现重叠,一起射,所用弓箭最少。全局最优:把所有气球射爆所用弓箭最少。
为了让气球尽可能的重叠,需要对数组进行排序。
如果气球重叠了,重叠气球中右边边界的最小值 之前的区间一定需要一个弓箭。

以题目示例: [[10,16],[2,8],[1,6],[7,12]]为例,如图:(方便起见,已经排序)
在这里插入图片描述

可以看出首先第一组重叠气球,一定是需要一个箭,气球3 的左边界大于了 第一组重叠气球的最小右边界,所以再需要一支箭来射气球3了。

版本一

初始化箭的数量为1,因为至少需要一支箭来射穿第一个气球。
从第二个气球开始遍历,检查每个气球的起始点与前一个气球的终点。
如果当前气球的起点大于前一个气球的终点,说明这两个气球不重叠,需要增加一支箭。
如果重叠,则更新当前气球的右边界为两者的较小值,以便下一次判断是否可以用同一支箭射穿。

class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        # 如果没有气球,返回0
        if len(points) == 0:
            return 0
        
        # 将气球按起始点升序排序
        points.sort(key=lambda x: x[0])
        
        # 初始化箭的数量为1,默认射出第一箭
        result = 1
        
        # 遍历排序后的气球列表,从第二个气球开始
        for i in range(1, len(points)):
            # 如果当前气球的起点大于前一个气球的终点,说明这两个气球不重叠,需要一支新的箭
            if points[i][0] > points[i - 1][1]:  # 注意这里用的是 '>' 而不是 '>='
                result += 1  # 增加箭的数量
            else:
                # 如果气球重叠,更新当前的最小右边界为两者中的较小值
                # 这样保证在重叠的气球中,一箭可以射穿所有重叠的气球
                points[i][1] = min(points[i - 1][1], points[i][1])
        
        # 返回总共需要的箭的数量
        return result

版本二

初始化最小左边界sl和最小右边界sr为第一个气球的位置。
初始化箭的数量为1,因为至少需要一支箭来射穿第一个气球。
遍历所有气球,对于每个气球,检查其起点与当前记录的最小右边界sr。
如果当前气球的起点大于sr,说明这些气球不重叠,需要一支新的箭,并更新最小左边界和最小右边界为当前气球的位置。
如果当前气球和之前的气球重叠,则更新最小左边界和最小右边界,以确保能用同一支箭射穿重叠的气球。

class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        # 将气球按起始点升序排序
        points.sort(key=lambda x: x[0])
        
        # 初始化最小左边界和最小右边界为第一个气球的位置
        sl, sr = points[0][0], points[0][1]
        
        # 初始化箭的数量为1
        count = 1
        
        # 遍历排序后的气球列表
        for i in points:
            # 如果当前气球的起点大于当前记录的最小右边界,说明需要一支新的箭
            if i[0] > sr:
                count += 1  # 增加箭的数量
                sl, sr = i[0], i[1]  # 更新最小左边界和最小右边界为当前气球的位置
            else:
                # 如果当前气球和之前的气球重叠,更新最小左边界和最小右边界
                sl = max(sl, i[0])  # 更新最小左边界为较大的起点
                sr = min(sr, i[1])  # 更新最小右边界为较小的终点
        
        # 返回总共需要的箭的数量
        return count

力扣题目链接
题目文章讲解
题目视频讲解

二、 力扣435. 无重叠区间

给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的 最小数量 ,使剩余区间互不重叠 。
示例
输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。

版本一

  1. 检查输入:
    如果intervals为空,直接返回0,因为没有区间需要处理。
  2. 排序:
    将区间按照左边界x[0]进行升序排序。这样可以保证后续的区间从左到右处理,方便判断是否重叠。
  3. 遍历区间:
    从第二个区间开始,检查当前区间的左边界是否小于前一个区间的右边界。
    如果重叠,更新当前区间的右边界为两个区间右边界的较小值,以减少后续的重叠可能性,并增加重叠计数count。
class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        if not intervals:
            return 0  # 如果区间列表为空,返回0

        intervals.sort(key=lambda x: x[0])  # 按照左边界升序排序
        
        count = 0  # 记录重叠区间的数量
        
        # 从第二个区间开始遍历
        for i in range(1, len(intervals)):
            if intervals[i][0] < intervals[i - 1][1]:  # 当前区间的左边界小于前一个区间的右边界,说明重叠
                # 如果重叠,更新当前区间的右边界为较小值,以减少后续的重叠可能性
                intervals[i][1] = min(intervals[i - 1][1], intervals[i][1])
                count += 1  # 记录一次重叠
        
        return count  # 返回需要移除的重叠区间的数量

版本二

  1. 检查输入:
    如果intervals为空,直接返回0,因为没有区间需要处理。
  2. 排序:
    将区间按照左边界x[0]进行升序排序,确保从左到右逐个处理区间。
  3. 初始化不重叠区间计数:
    result初始值设为1,因为至少会有一个不重叠的区间(第一个区间)。
  4. 遍历区间:
    从第二个区间开始,检查当前区间的左边界是否大于等于前一个区间的右边界。
    如果不重叠,增加不重叠区间的计数result。
    如果重叠,更新当前区间的右边界为两个区间右边界的较小值,以减少后续的重叠可能性。
class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        if not intervals:
            return 0  # 如果区间列表为空,返回0
        
        intervals.sort(key=lambda x: x[0])  # 按照左边界升序排序
        
        result = 1  # 记录不重叠区间的数量,初始化为1,因为至少有一个不重叠的区间
        
        # 从第二个区间开始遍历
        for i in range(1, len(intervals)):
            if intervals[i][0] >= intervals[i - 1][1]:  # 当前区间的左边界大于等于前一个区间的右边界,说明不重叠
                result += 1  # 不重叠的区间数加1
            else:  # 如果重叠
                # 更新当前区间的右边界为较小值,以减少后续的重叠可能性
                intervals[i][1] = min(intervals[i - 1][1], intervals[i][1])
        
        # 总区间数减去不重叠的区间数,就是需要移除的区间数
        return len(intervals) - result

力扣题目链接
题目文章讲解
题目视频讲解

三、 力扣763. 划分字母区间

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。
返回一个表示每个字符串片段的长度的列表。
示例
输入:s = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释
划分结果为 “ababcbaca”、“defegde”、“hijhklij” 。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 这样的划分是错误的,因为划分的片段数较少。

在遍历的过程中相当于是要找每一个字母的边界,**如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。**此时前面出现过所有字母,最远也就到这个边界了。

可以分为如下两步:

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

如图:
在这里插入图片描述

版本一

  1. 记录字符的最后出现位置:

使用字典last_occurrence记录每个字符在字符串中最后出现的位置。通过遍历字符串,将每个字符的最新位置存入字典。

  1. 初始化变量:

result用于存储最终划分出的每个区间的长度。
start和end分别表示当前区间的起始和结束位置。

  1. 遍历字符串进行区间划分:

在遍历字符串时,不断更新当前区间的结束位置end为当前字符的最后出现位置。
当当前位置i等于end时,意味着当前区间可以结束,将这个区间的长度添加到结果中,并更新起始位置start。

class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        last_occurrence = {}  # 存储每个字符最后出现的位置
        for i, ch in enumerate(s):
            last_occurrence[ch] = i  # 记录字符ch在字符串s中的最后出现位置

        result = []  # 存储每个区间的长度
        start = 0  # 当前区间的起始位置
        end = 0  # 当前区间的结束位置
        
        for i, ch in enumerate(s):
            # 更新当前区间的结束位置为字符ch最后出现的位置
            end = max(end, last_occurrence[ch])  
            
            # 如果当前位置i是当前区间的结束位置,则完成一个区间的划分
            if i == end:
                result.append(end - start + 1)  # 将区间的长度加入结果列表
                start = i + 1  # 更新起始位置为下一个字符的位置
        
        return result  # 返回划分出的区间长度列表

版本二

  1. 统计每个字符的起始和结束位置:

countLabels函数通过遍历字符串,记录每个字母的起始和结束位置。使用长度为26的数组hash存储这些位置,hash[i][0]表示字母i的起始位置,hash[i][1]表示字母i的结束位置。

  1. 过滤有效的区间:

遍历hash数组,过滤掉未出现的字母,只保留有效的区间信息,存入hash_filter列表。

  1. 排序区间:

按照区间的左边界从小到大排序,为后续区间合并和划分做准备。

  1. 遍历区间进行划分:

初始化rightBoard为第一个区间的右边界,leftBoard为0。
遍历排序后的区间列表,若发现当前区间的左边界大于当前的最大右边界,说明可以划分出一个新的区间。更新左边界和右边界,并记录划分出的区间长度。

  1. 添加最后一个区间:

在循环结束后,别忘了添加最后一个区间的长度。

class Solution:
    def countLabels(self, s):
        # 初始化一个长度为26的区间列表,用于记录每个字母的起始和结束位置
        hash = [[float('-inf'), float('-inf')] for _ in range(26)]
        hash_filter = []
        
        # 遍历字符串,记录每个字母的起始和结束位置
        for i in range(len(s)):
            # 如果当前字母第一次出现,记录它的起始位置
            if hash[ord(s[i]) - ord('a')][0] == float('-inf'):
                hash[ord(s[i]) - ord('a')][0] = i
            # 更新当前字母的结束位置为最新位置
            hash[ord(s[i]) - ord('a')][1] = i
        
        # 过滤掉没有出现的字母,生成有效的区间列表
        for i in range(len(hash)):
            if hash[i][0] != float('-inf'):
                hash_filter.append(hash[i])
        
        return hash_filter  # 返回有效的区间列表

    def partitionLabels(self, s):
        res = []
        hash = self.countLabels(s)  # 获取有效的区间列表
        hash.sort(key=lambda x: x[0])  # 按左边界从小到大排序
        
        rightBoard = hash[0][1]  # 初始化最大右边界为第一个区间的右边界
        leftBoard = 0  # 初始化左边界为0
        
        for i in range(1, len(hash)):
            # 如果当前区间的左边界大于当前的最大右边界,说明可以划分一个新的区间
            if hash[i][0] > rightBoard:
                res.append(rightBoard - leftBoard + 1)  # 添加划分的区间长度到结果列表
                leftBoard = hash[i][0]  # 更新左边界为当前区间的左边界
            
            # 更新当前的最大右边界
            rightBoard = max(rightBoard, hash[i][1])
        
        # 添加最后一个区间的长度到结果列表
        res.append(rightBoard - leftBoard + 1)
        
        return res  # 返回划分出的区间长度列表

力扣题目链接
题目文章讲解
题目视频讲解

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YoloV8改进策略:Block改进|LeYOLO,一种用于目标检测的新型可扩展且高效的CNN架构|复现LeYolo,轻量级Yolo改进

摘要 在目标检测中&#xff0c;深度神经网络的计算效率至关重要&#xff0c;尤其是随着新型模型越来越注重速度而非有效计算量&#xff08;FLOP&#xff09;。这一发展趋势在某种程度上忽视了嵌入式和面向移动设备的AI目标检测应用。在本文中&#xff0c;我们基于FLOP关注于高…

热泵干燥应用举例

热泵在木材加工中的应用主要是热泵干燥&#xff0c;具有能耗低、干燥质量好等特点。热泵木材干燥装置的基本结构是封闭式干燥窑&#xff0c;其中热泵机组的结构有单热源型&#xff08;图18-4&#xff09;、双热源型&#xff08;图18-5&#xff09;和空气回热型&#xff08;图18…

深入理解Java中的ConcurrentHashMap:高效线程安全的并发容器

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

Java并发:内存屏障,Atomic类,CAS函数,伪共享

阅读本文之前可以看一看 Java 多线程基础&#xff1a; Java&#xff1a;多线程&#xff08;进程线程&#xff0c;线程状态&#xff0c;创建线程&#xff0c;线程操作&#xff09; Java&#xff1a;多线程&#xff08;同步死锁&#xff0c;锁&原子变量&#xff0c;线程通信&…

【学习笔记】A2X通信的协议(十)- 通过PC5的直接探测与避让(DDAA)

3GPP TS 24.577 V18.1.0的技术规范&#xff0c;主要定义了5G系统中A2X通信的协议方面&#xff0c;特别是在PC5接口和Uu接口上的A2X服务。以下是文件的核心内容分析&#xff1a; 8. 通过PC5的直接探测与避让&#xff08;DDAA&#xff09; 8.1 概述 本条款描述了UE之间以及UE上…

论文阅读:Efficient Core Maintenance in Large Bipartite Graphs | SIGMOD 2024

还记得我们昨天讨论的《Querying Historical Cohesive Subgraphs over Temporal Bipartite Graphs》这篇论文吗? https://blog.csdn.net/m0_62361730/article/details/141003301 这篇(还没看的快去看) 这篇论文主要研究如何在时间双向图上查询历史凝聚子图&#xff0c;而《E…

CAD二次开发IFoxCAD框架系列(18)-块表操作

1. 块表的查询 1.1 查找名为“自定义块”的块表中的图块记录 using var tr new DBTrans(); if (tr.BlockTable.Has("自定义块")) {//要执行的操作 }遍历块表并打印所有的块表的图块名称 public void Test_DBTrans_BlockCount() {using var tr new DBTrans();var…

CentOS7.9上通过KVM安装Centos虚拟机

目录 1 开发前准备&#xff08;先确保服务器可以虚拟化&#xff09;&#xff1a; 2、安装KWM环境 3、创建镜像文件存放目录 4、创建镜像文件存放目录 5、安装桥连接虚拟网络 6、安装虚拟机 7、配置操作系统 8、虚拟机配置网卡地址 9、克隆虚拟机执行 1开发前准备&am…

Git文件管理技巧:轻松删除与查看文件,忽略不必要的文件与文件夹!

避免文件混乱&#xff1a;Git 文件操作技巧 一、Git工作原理概述二、删除文件三、查看指定文件的修改四、指定不需要 Git 管理的文件五、总结 一、Git工作原理概述 Git是一种分布式版本控制系统&#xff0c;其核心在于其高效的快照机制、强大的分支与合并功能、本地开发的灵活…

数据集与数据库:有什么区别?

数据集和数据库是我们在处理数据时经常听到的两个常用词。虽然它们听起来很相似&#xff0c;但它们具有不同的特征并用于不同的用途。本文深入探讨数据集和数据库之间的主要区别&#xff0c;探索了它们的结构、数据类型和各种其他功能&#xff0c;以帮助您做出明智的决定&#…

回归预测|基于灰狼优化GWO-Transformer-BiLSTM组合模型的数据回归预测Matlab程序 多特征输入单输出

回归预测|基于灰狼优化GWO-Transformer-LSTM组合模型的数据回归预测Matlab程序 多特征输入单输出 文章目录 前言回归预测|基于灰狼优化GWO-Transformer-BiLSTM组合模型的数据回归预测Matlab程序 多特征输入单输出GWO-Transformer-BiLSTM 一、GWO-Transformer-BiLSTM模型二、实验…

uniapp打包H5的时候 清楚缓存(不安装依赖的前提下)

问题 在写项目的时候&#xff0c;打包好一个H5 发布成功&#xff0c;后来又重新打包新的包进行更新迭代&#xff0c;但是用户手机上还是上一个版本&#xff0c;本地缓存还是没有清除。 解决问题 步骤一&#xff1a;html不缓存 在html中&#xff0c;解决缓存的方法主要是依赖…

文章解读与仿真程序复现思路——电力自动化设EI\CSCD\北大核心《海上风电全直流汇集送出系统自适应振荡抑制策略》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

【小bug】springMVC通过json传参无法解析参数

0.问题描述 通过postman测试使用json传参的时候&#xff0c;发现不论怎么修改&#xff0c;都无法获取参数&#xff0c;解析对象。 反复检查请求url&#xff0c;请求内容均为正常。 以下是postman测试结果&#xff1a; 日志提示无法解析参数&#xff0c;内容如下&#xff1a;…

C# VideoCapture 多路视频播放

目录 效果 项目 代码 下载 效果 C#VideoCapture多路视频播放 项目 代码 using OpenCvSharp; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks…

MS5046T/5047T/5048T/5048N_2kSPS、16bit Σ-Δ ADC

MS5046T/MS5047T/MS5048T/MS5048N 是适合高精 度、低成本测量应用的 16bit 模数转换器。其内部集成低 噪声可编程增益放大器、高精度 Δ-Σ 模数转换器和内部振 荡器。 MS5047T 、 MS5048T 、 MS5048N 内部还集成低温 漂基准和两路匹配的可编程电流源。 MS5048T/MS50…

计算机毕业设计 健身房管理系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

springboot考勤管理系统代码调试讲解论文

2 相关技术 2.1 MySQL数据库 该研究和开发的应用程序在数据操作中难以预料&#xff0c;有时候甚至发生改变。没办法直接从Word中写数据和信息&#xff0c;这不但不安全的&#xff0c;并且难以实现应用程序的功效。要实现所需要的文档存储作用&#xff0c;请尽快选择专业数据存…

【JPCS独立出版,EI稳定检索】2024年工业机器人与先进制造技术国际学术会议(IRAMT 2024,9月27-29)

2024年工业机器人与先进制造技术国际学术会议&#xff08;IRAMT 2024&#xff09;将于2024年9月27-29日在中国成都举办。 此次会议将围绕工业机器人、机电技术、机械及制造等领域的最新研究成果展开讨论&#xff0c;并广泛邀请了国内外领域内的著名专家与学者。会议旨在搭建一个…

Vision Transformer学习笔记

论文链接&#xff1a;https://arxiv.org/abs/2010.11929 项目链接&#xff1a;https://github.com/google-research/vision_transformer 本文代码链接&#xff1a;https://gitcode.com/gh_mirrors/de/deep-learning-for-image-processing/tree/master/pytorch_classification/v…