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

news2024/9/21 16:46:11

文章目录

    • 452.用最少数量的箭引爆气球
      • 思路
    • 435.无重叠区间
      • 思路
    • 763.划分字母区间
      • 思路
        • 问题的转化
    • 总结

今天是贪心算法专题的第四天,今天的三道题目,都算是 重叠区间 问题,大家可以好好感受一下。 都属于那种看起来好复杂, 但一看贪心解法,惊呼:这么巧妙

这种题还是属于那种,做过了也就会了,没做过就很难想出来

不过大家把如下三题做了之后, 重叠区间 基本上差不多了

452.用最少数量的箭引爆气球

题目链接:452. 用最少数量的箭引爆气球 - 力扣(LeetCode)

思路

每一个重叠区间共用一个箭(局部最优),才能做到用最少的箭引爆气球(全局最优),因此我们要让各个气球的区间尽可能重叠,如果气球重叠了,重叠气球中右边界的最小值 之前的区间一定需要一个弓箭,实际上,有多少个不重叠的区间,就需要多少个箭,因此选择右边界排序,统计不重叠区间的个数

以题目示例: [[10,16],[2,8],[1,6],[7,12]],排序后:

可以看到,第一组重叠区间,pos = 6,需要一个箭,气球3的 左边界 > pos,气球3不在第一组重叠区间内,要更新pos = 7,即第二组重叠区间的最小右边界,arrow++,需要一个箭

代码实现

class Solution {
public:
    static bool cmp(const vector<int>& a, const vector<int>& b)
    {
        return a[1] < b[1];
    }
    int findMinArrowShots(vector<vector<int>>& points) {
        if(points.empty())
        {
            return 0;
        }
        sort(points.begin(), points.end(), cmp);
        int arrow = 1;
        int pos = points[0][1]; // 初始pos为第一个区间的右边界
        
        for(int i=1; i<points.size(); ++i)
        {
            if(pos >= points[i][0]) // 重叠区间,共用一支箭
            {
                continue;
            }
            pos = points[i][1]; // 将pos更新为下一个边界的右区间
            arrow++;
        }
        return arrow;
    }
};

435.无重叠区间

题目链接:435. 无重叠区间 - 力扣(LeetCode)

思路

这道题与 452.用最少数量的箭引爆气球 很类似,452.用最少数量的箭引爆气球 中寻找重叠区间的个数,这道题需要寻找不重叠区间的个数,思想是一致的——先将数组按照有边界排序,然后遍历数组,令end = 当前重叠区间的最小右边界,然后比较end 与 intervals[i] [0]的大小,由于要寻找不重叠区间的个数,我们要在end <= intervals[i] [0]时将count++,同时更新end = intervals[i] [1],即下一个重叠区间的最小右边界

代码如下

class Solution {
public:
    // 按照区间右边界排序
    static bool cmp (const vector<int>& a, const vector<int>& b) {
        return a[1] < b[1];
    }
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        if (intervals.size() == 0) return 0;
        sort(intervals.begin(), intervals.end(), cmp);
        int count = 1; // 记录非交叉区间的个数
        int end = intervals[0][1]; // 记录区间分割点
        for (int i = 1; i < intervals.size(); i++) {
            if (end <= intervals[i][0]) {
                end = intervals[i][1];
                count++;
            }
        }
        return intervals.size() - count;
    }
};

或者左边界排序,直接求要移除的区间个数:

class Solution {
public:
    static bool cmp (const vector<int>& a, const vector<int>& b) {
        return a[0] < b[0]; // 改为左边界排序
    }
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        if (intervals.size() == 0) return 0;
        sort(intervals.begin(), intervals.end(), cmp);
        int count = 0; // 注意这里从0开始,因为是记录重叠区间
        for (int i = 1; i < intervals.size(); i++) {
            if (intervals[i][0] < intervals[i - 1][1]) { //重叠情况
                intervals[i][1] = min(intervals[i - 1][1], intervals[i][1]);	// 这里用的是min,这是为了尽量减少后续的重叠,选择移除右边界较大的区间(即 end 更新为两个重叠区间中右边界较小的那个),并不是统计重叠区间的个数
                count++;
            }
        }
        return count;
    }
};

763.划分字母区间

题目链接:763. 划分字母区间 - 力扣(LeetCode)

思路

问题的转化

可以将这道题转化为重叠区间问题。我们首先统计每个字母出现的起始位置,获得appearIntervals,它记录了s中每个字符的[start, end]

题目要求每个字母至多在一个片段中出现,片段尽量多,因此每个片段对应一个重叠区间,片段的分割点就是重叠区间的右边界,我们使用左边界排序,记录每个重叠区间的start和end,重叠区间的长度就是end - start + 1

代码如下

class Solution {
public:
    static bool cmp(const vector<int>& a, const vector<int>& b)
    {
        return a[0] < b[0];
    }
    vector<vector<int>> CountIntervals(string s)
    {
        vector<vector<int>> intervals(26, vector<int>(2,-1));
        vector<vector<int>> appearIntervals;
        // 首先统计每个字符出现的区间
        for(int i=0; i<s.size(); ++i)
        {
            int index = s[i] - 'a';
            if(intervals[index][0] == -1)
            {
                intervals[index][0] = i;
            }
            intervals[index][1] = i;
        }
        // 筛选出现过的字符区间
        for(int i=0; i<intervals.size(); ++i)
        {
            if(intervals[i][1] != -1)
            {
                appearIntervals.push_back(intervals[i]);
            }
        }
        return appearIntervals;
    }
    vector<int> partitionLabels(string s) {
        vector<vector<int>> appearIntervals = CountIntervals(s);
        // 寻找重叠区间,记录每个重叠区间的最大右边界,即为断点
        sort(appearIntervals.begin(), appearIntervals.end(), cmp);
        int end = appearIntervals[0][1];    // 记录每个重叠区间的终止位置
        int start = appearIntervals[0][0];
        vector<int> result;

        for(int i=1; i<appearIntervals.size(); ++i)
        {
            if(end > appearIntervals[i][0])
            {
                end = max(end, appearIntervals[i][1]);
            }else
            {
                result.push_back(end - start + 1);
                end = appearIntervals[i][1]; 
                start = appearIntervals[i][0];
            }
        }
        result.push_back(end - start + 1);  // 最后一个重叠区间

        return result;
    }
};

总结

对于重叠区间问题:有两种排序方法:按照左边界(起始位置)排序 和 按照右边界(终止位置)排序

  • 按照左边界排序,用于统计重叠区间的个数:

    排序

    • 首先,代码将区间按照左边界进行排序,使得左边界较小的区间排在前面。

    初始化

    • count 初始化为 0,表示当前还没有发现重叠的区间。
    • end 初始化为第一个区间的右边界,表示当前正在处理的区间的右边界。

    遍历区间

    • 对于每个区间,判断它的左边界是否小于当前记录的 end
    • 重叠情况:如果当前区间的左边界小于 end,表示当前区间与之前的区间有重叠,count 增加 1,表示发现了一个重叠区间,同时更新 end 为当前区间和前一个区间的右边界的最大值。
    • 无重叠情况:如果当前区间的左边界大于等于 end,表示当前区间与之前的区间没有重叠,直接更新 end 为当前区间的右边界。

    返回结果

    • 最终 count 的值就是统计到的重叠区间的个数。
    class Solution {
    public:
        static bool cmp (const vector<int>& a, const vector<int>& b) {
            return a[0] < b[0]; // 左边界排序
        }
        int findIntervals(vector<vector<int>>& intervals) {
            if (intervals.size() == 0) return 0;
            sort(intervals.begin(), intervals.end(), cmp);
            int count = 0; // 注意这里从0开始
            int end = intervals[0][1];	// 第一个重叠区间的右边界
            for (int i = 1; i < intervals.size(); i++) {
                //重叠情况
                if (end > intervals[i][0]) { 
                    count++;
                    end = max(end, intervals[i][1]);	// 更新当前重叠区间的终止位置
                }else
                {
                    end = intervals[i][1];
                }
            }
            return count;
        }
    };
    

以[[1,2],[2,3],[3,4],[1,3]]为例,重叠区间的个数为2:

[1,2][1,3] 是重叠的,因为 [1,2][1,3] 之间有交集 [1,2]

[2,3][1,3] 也是重叠的。

[3,4] 和其他区间没有重叠

  • 按照右边界排序,用于统计不重叠区间的个数:

    排序

    • 代码首先将区间按右边界进行排序,使得右边界较小的区间排在前面。

    初始化

    • count 初始化为 1,表示第一个区间已经被选中,因此至少有一个非重叠区间。
    • end 初始化为第一个区间的右边界,表示当前选中区间的右边界。

    遍历区间

    • 对于每个区间,判断当前区间是否与前一个选中的非重叠区间重叠。
    • 无重叠情况:如果当前区间的左边界大于或等于 end,表示当前区间与之前的选中区间没有重叠,将 end 更新为当前区间的右边界,并将 count 加 1,表示找到了一个新的非重叠区间。
    • 重叠情况:如果当前区间的左边界小于 end,表示当前区间与之前的区间有重叠,但不执行任何操作,继续寻找下一个区间。
    class Solution {
    public:
        // 按照区间右边界排序
        static bool cmp (const vector<int>& a, const vector<int>& b) {
            return a[1] < b[1];
        }
        int findIntervals(vector<vector<int>>& intervals) {
            if (intervals.size() == 0) return 0;
            sort(intervals.begin(), intervals.end(), cmp);
            int count = 1; // 记录非交叉区间的个数
            int end = intervals[0][1]; // 记录区间分割点
            for (int i = 1; i < intervals.size(); i++) {
                // 不重叠情况
                if (end <= intervals[i][0]) {
                    end = intervals[i][1];
                    count++;
                }
            }
            return count;
        }
    };
    

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

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

相关文章

携手共创商业新纪元,聚贤国际成都分部正式成立

成大事者&#xff0c;聚于府都。2024年8月10日&#xff0c;在成都这个西部经济中心城市&#xff0c;聚贤国际成都分部正式成立&#xff0c;标志着聚贤国际商会在这片营商沃土落地生根。 本次成都分部成立&#xff0c;特别邀请到聚贤国际创始人刘芒芒及聚贤国际商会三亚分部、海…

ubuntu20.04源码编译安装qemu(qemu8.2)

ubuntu20.04源码安装qemu8.2 本文用于记录在ubuntu20中源码编译安装qemu8.2&#xff0c;同时也希望能够对你有所帮助。 一、download qemu 根据自己的需求下载对应版本的qemu源码压缩包。 https://github.com/qemu/qemu/tags二、build qemu 解压缩后&#xff0c;执行下述命令。…

一文读懂高通GPU驱动渲染流程

1. gpu command分析 1.1 gpu command概述 SM8650平台上&#xff0c;GLES发送给KMD&#xff08;GPU驱动&#xff09;的GPU命令有两种类型&#xff1a;同步命令和绘制命令。 绘制命令&#xff0c;一般都是一个个的drawcall组成的&#xff0c;是真正GPU程序指令&#xff0c;KMD会给…

自动分班实用工具

开学前夕&#xff0c;老师们的日程表上又添上了一笔笔的工作任务。分班&#xff0c;作为开学前的一项重要工作&#xff0c;不仅关系到学生的学习环境&#xff0c;也是家长们关注的焦点。 易查分&#xff0c;让分班变得简单 易查分小程序的出现&#xff0c;为老师们提供了一种全…

Vercel 的 AI 工具 V0.dev:如何使用它?

几个月前&#xff0c;Vercel 宣布推出了 V0.dev&#xff0c;这是一款专为开发人员和设计师设计的工具&#xff0c;能够使用 AI 生成 React 代码。最初&#xff0c;V0.dev 对外开放时采用了邀请制&#xff0c;但如今拥有 Vercel 帐户的任何人都可以访问并使用它。 这些工具填补…

计算机专业的 “铁饭碗” 终于被发现啦

计算机专业毕业后只能当码农吗&#xff1f;大错特错❌&#xff01;其实计算机专业考公真的非常有优势呢&#xff01;张雪峰就曾说过&#xff1a;“计算机在考公的时候&#xff0c;有那种 yyds 的感觉&#xff0c;是所有单位都要。”&#x1f603; &#x1f33b;计算机类专业包…

音频播放+音频采样(绘制音波)

引言 在 iOS 平台中&#xff0c;实现音频播放有多种方式。AVAudioPlayer 是一个专门用于播放音频数据的类&#xff0c;易于使用&#xff0c;适合处理简单的音频播放需求。而 AVPlayer 则是一种更通用的播放器&#xff0c;既能播放视频资源&#xff0c;也能处理音频内容&#x…

Linux:Linux线程池

目录 线程池的概念 线程池的优点 线程池的应用场景 线程池的实现 线程池演示 线程池的概念 线程池是一种线程使用模式。 线程过多会带来调度开销&#xff0c;进而影响缓存局部和整体性能&#xff0c;而线程池维护着多个线程&#xff0c;等待着监督管理者分配可并发执行的…

长视频生成研究的挑战、方法与前景

人工智能咨询培训老师叶梓 转载标明出处 长视频生成面临的主要挑战包括如何在有限的计算资源下生成长时间、高一致性、内容丰富且多样化的视频序列。另外现有研究中对于“长视频”的定义并不统一&#xff0c;这给研究的标准化和比较带来了困难。来自西安电子科技大学、上海交通…

Window 安装Gogs教程

1、下载 下载地址&#xff1a;https://gogs.io/docs/installation/install_from_binary.html(请自行科学上网 选择Windows amd64(64位)或者386(32位) 2、安装 2.1 将压缩文件放到目标文件夹 2.2 创建数据库 在本地数据库或者其他目标数据库新建查询执行下列SQL语句 找到go…

taskBus的设计局限和吞吐能力测试

在前文中&#xff0c;我们介绍了EPDR技术的起源&#xff0c;以及使用该技术驱动的业余软件无线电平台专栏。已有玩家通过踩坑证明&#xff0c;进程管道交换数据时间延迟大&#xff08;10ms&#xff09;&#xff0c;构造时间敏感系统难。除非采用传统的紧耦合设计及更大的颗粒度…

尚品汇-选中状态缓存变更、删除缓存购物车(三十八)

目录&#xff1a; &#xff08;1&#xff09;选中状态的变更 &#xff08;2&#xff09;删除购物车 &#xff08;3&#xff09;流程总结 &#xff08;1&#xff09;选中状态的变更 用户每次勾选购物车的多选框&#xff0c;都要把当前状态保存起来。由于可能会涉及更频繁的操…

基于AT89C51单片机的可手动定时控制的智能窗帘设计

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/89469560?spm=1001.2014.3001.5503 C 源码+仿真图+毕业设计+实物制作步骤+11 摘要 I abstract II 第1章 绪论 1 1.1 背景及意义 1 1.2 国内外发展现状 1 1.3 设计思想及基…

ChatGPT等大模型高效调参大法——PEFT库的算法简介

随着ChatGPT等大模型&#xff08;Large Language Model&#xff09;的爆火&#xff0c;而且目前业界已经发现只有当模型的参数量达到100亿规模以上时&#xff0c;才能出现一些在小模型无法得到的涌现能力&#xff0c;比如 in_context learing 和 chain of thougt。深度学习似乎…

Excel如何快速的定位到某一列和快速知道当前列

Excel如何快速的定位到某一列和快速知道当前列 背景快速找到某一列---660列快速知道当前列 背景 由于某一次做excel数据太大需要快速知道某一列是多少列和快速定位到某一列对此写了这个 快速找到某一列—660列 SUBSTITUTE(ADDRESS(1, 660, 4), "1", ""…

实现MySQL的主从复制基础

目录 1 MySQL实现主从复制的原理 1.1 实现主从复制的规则 1.2 如何实现主从复制 2 MySQL 实现主从复制实践 2.1 实验环境 2.2 my.cnf 配置添加 2.2.1 配置MSTER 端配置文件 2.2.2 配置SLAVE 端配置文件 2.2.3 三台MySQL服务器重启服务 2.3 创建用于复制的用户 2.4 保证三台主机…

Android实战:过root检测

在启动这个app时&#xff0c;我们会看到一个提示&#xff0c;表示设备处于root环境。如下图所示&#xff1a; 为了过掉到这个root检测&#xff0c;我们可以通过直接Hook Toast.show()方法&#xff0c;并打印调用堆栈信息来实现定位关键代码。以下是相关的Frida脚本代码&#…

esxi 安装 精简版win10

镜像来源&#xff1a;[【不忘初心】Windows10 22H2 (19045.4780) X64 无更新 纯净[深度精简版]1.27G](https://www.pc528.net/22h2s.html) 提供下载地址&#xff1a;https://www.123pan.cn/s/lYtRVv-Wmuf3?提取码:GaD4 先把下载esd 转成iso安装 把下载的esd 重命名为install…

如何使用ssm实现学生宿舍管理

TOC ssm094学生宿舍管理jsp 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范化管理。这样…

YOLOv5改进 | 融合改进 | C3融合EffectiveSE-Convolutional【完整代码 + 小白必备】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录&#xff1a; 《YOLOv5入门 改…