Studying-代码随想录训练营day31| 56.合并区间、738.单调递增的数字、968.监控二叉树、贪心算法总结

news2024/9/20 22:01:28

第31天,贪心最后一节(ง •_•)ง💪,编程语言:C++

目录

56.合并区间

738.单调递增的数字

968.监控二叉树 

贪心算法总结 


56.合并区间

文档讲解:代码随想录合并区间

视频讲解:手撕合并区间

题目:

学习:本题属于区间问题,同样是找到重合的区间,与用最少数量的箭引爆气球和无重叠区间问题解法是相同的。

本题可以先对区间进行排序,便于找到重叠区间,可以依照每个区间的左边界从小到大排序。之后比较后续区间的左边界,与前一个区间的右边界的关系,判断是否重叠。如果不重叠,则加入答案数组中,如果重叠则更新最大右边界。

代码:

//时间复杂度O(nlogn)快速排序时间复杂度
//空间复杂度O(logn)快速排序空间复杂度
class Solution {
public:
    static bool camp(vector<int>& a, vector<int>& b) {
        return a[0] < b[0];
    }
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        //先进行排序,按照开始节点进行排序
        sort(intervals.begin(), intervals.end());
        vector<vector<int>> result; //返回数组
        //初始化左右边界
        int left = intervals[0][0];
        int right = intervals[0][1];
        for(int i = 1; i < intervals.size(); i++) {
            if(intervals[i][0] <= right) {
                right = max(right, intervals[i][1]);
            }
            else {
                result.push_back({left, right});
                right = intervals[i][1];
                left = intervals[i][0];
            }
        }
        //把最后一个点加入
        result.push_back({left, right});
        return result;
    }
};

本题还可以不设置单独的left,right来作为左边边界,而是使用back()来作为右边界进行更新。同时由于我们提前进行了排序,左边界又能够保证是按从小到大顺序进入的。

代码:

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        //使用lambda表达式
        sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){return a[0] < b[0];});
        vector<vector<int>> result; //返回数组
        //使用back()来确定
        result.push_back(intervals[0]); //初始化区间

        for(int i = 1; i < intervals.size(); i++) {
            if(intervals[i][0] <= result.back()[1]) {
                result.back()[1] = max(result.back()[1], intervals[i][1]);
            }
            else {
                result.push_back(intervals[i]);
            }
        }
        return result;
    }
};

738.单调递增的数字

文档讲解:代码随想录单调递增的数字

视频讲解:手撕单调递增的数字

题目:

学习:本题重点在于需要比较每个位上的大小,来判断是否是单调递增的。贪心的方法就在于如果数不是单调递增的该如何处理。假设出现 num[i - 1] > num[i] 的情况,也就是前一位比后一位大的情况。由于需要单调递增,且不允许增大数,因此我们的贪心逻辑是,一旦出现num[i - 1] > num[i]的情况,我们就将前一位num[i - 1]--,同时将num[i]及以后的位变为9,这样就既能保证单调递增,数又是最大的。

本题我们需要从后往前遍历,我们需要利用后面比较的结果。以332为例子,如果从前往后遍历,将得到329,显然答案不对。如果从后往前遍历则是299,显然最终答案应该是这个。

写代码的时候可以注意两个关键点:

  1. 可以利用to_string()函数将数字变换为字符串,方便进行遍历处理。最后可以通过stoi()函数将字符串重新转变为int型变量。
  2. 可以设置一个flag位,确定后续要变9的位置,显然,我们只要找到最后一个需要减1的位置,后面的位就是需要置为9的。

代码:

//时间复杂度O(n)
//空间复杂度O(n)
class Solution {
public:
    int monotoneIncreasingDigits(int n) {
        //从后往前遍历,遇到前面的数大的情况,进行“前减一,后置9”的操作
        string str = to_string(n); //为了方便遍历,将int型变量转换为字符串(★)
        int flag = str.size(); //记录需要后置为9的位置
        //找到最后一个不单调的位置
        for(int i = str.size() - 1; i > 0; i--) {
            if(str[i] < str[i - 1]) {
                flag = i; //记录需要变9的位置
                str[i - 1]--; //进行减1
            } 
        }
        for(int i = flag; i < str.size(); i++) {
            str[i] = '9'; //进行变9
        }
        return stoi(str);
    }
};

968.监控二叉树 

文档讲解:代码随想录监控二叉树

视频讲解:手撕监控二叉树

题目:

学习:本题的关键在于,思考如何放置摄像头才能使得摄像头的数量最小。从例子中我们可以发现,摄像头均没有放在叶子节点上。我们知道摄像头能够覆盖上中下三层,如果摄像头放在叶子节点上就必然会使得有一层是浪费的。虽然头节点放摄像头也会使得浪费一层,但是相较于头节点,叶子节点显然更多,因此叶子节点不放摄像头数量节省下来的是指数阶的。

本题的贪心就在于,局部最优:让叶子节点的父节点安装摄像头,摄像头数量最少;整体最优:全部摄像头数量所用最少。

理解了上述的贪心逻辑,我们还需要解决如下两个问题:1.二叉树的遍历;2.如何隔两个节点放一个摄像头。

1.二叉树的遍历顺序,显然我们要保证叶子节点的父节点有摄像头,且要尽可能的少放摄像头,我们需要从底往上,判断当前位置是否被覆盖,是否放置摄像头。因此需要采用后序遍历的方式。

2.如何隔两个节点放一个摄像头,对于一个节点来说,可能存在3种状态:没有被覆盖,该处有摄像头,该处没有摄像头但是被覆盖。而对于一个节点是否要安装一个摄像头,我们就需要判断左右孩子处于什么状态,如果左右孩子有一个处于没有被覆盖的状态,我们就需要在当前节点安装一个摄像头,并告诉其父节点自身有摄像头。

基于以上需求,我们可以设置3个数字来表示,当前节点的状态:

  • 0:该节点无覆盖
  • 1:本节点有摄像头
  • 2:本节点有覆盖。

然后通过递推关系,来判断当前节点应该处于什么状态。如果处于1状态,我们就需要记录一个摄像头。

接下来我们就需要进行遍历过程中,递归三部曲的设置了:

1.确定返回值和参数列表:由于我们需要使用三个数字来表示当前节点的状态,因此我们返回值需设置为int型,参数列表传入root。

2.确定终止条件:由于我们需要左右孩子的情况,来判断当前节点处于的状态,因此我们需要遍历到最后的空节点(解决只有左右一个孩子的情况),而对于空节点应该处于什么状态,我们需要进行确定。为了让叶子节点不放摄像头,而叶子节点的父节点放摄像头,则叶子节点应该处于无覆盖的情况,且不能放置摄像头,因此空节点应该处于的是有覆盖的情况,这样才能推出叶子节点是无覆盖的。

3.单层递归逻辑:采用的是后序遍历,而后我们需要处理的“中”逻辑有四种情况:

  • 左右节点都有覆盖:则此时中间节点就应该是无覆盖的情况
  • 左右节点至少有一个无覆盖的情况:则中间节点应该安装一个摄像头。
  • 左右节点至少有一个有摄像头:则中间节点处于有覆盖的情况。
  • 头结点没有覆盖:头节点我们需要单独进行处理,因为头节点可能处于没有覆盖的情况。

基于以上,我们可以写出代码:

//时间复杂度O(n)
//空间复杂度O(n)
class Solution {
public:
    int result = 0; //定义全局变量,记录摄像头的个数
    //遍历树,1.确定返回值和参数列表
    //我们使用0,1,2来表示当前节点的三种状态:无覆盖(0)、有摄像头(1)、有覆盖(2);
    int traversal(TreeNode* root) {
        //确定终止条件
        if(root == nullptr) {
            return 2; //为了让叶子节点的父节点安装摄像头,空节点应设置为有覆盖,这样遍历到叶子节点默认左右孩子为有覆盖自身为无覆盖。
        }
        //采用后续遍历的方式,进行单层递归逻辑
        int left = traversal(root->left); //左
        int right = traversal(root->right); //右
        //中:分为三种情况
        //1.左右孩子均为有覆盖
        if(left == 2 && right == 2) {
            return 0; //则当前节点返回无覆盖
        }
        //2.左右孩子有一个是无覆盖(包含了5种情况)
        // left == 0 && right == 0 左右节点无覆盖
        // left == 1 && right == 0 左节点有摄像头,右节点无覆盖
        // left == 0 && right == 1 左节点有无覆盖,右节点摄像头
        // left == 0 && right == 2 左节点无覆盖,右节点覆盖
        // left == 2 && right == 0 左节点覆盖,右节点无覆盖
        if(left == 0 || right == 0) {
            result++; //则该节点需要有一个摄像头
            return 1;
        }

        //3.在上一个情况筛选的基础上,左右孩子有一个是有摄像头的
        if(left == 1 || right == 1) {
            return 2; //返回有覆盖
        }
        return -1; //在没有写else的情况下,需要加一个return,但实际上该return不会运行到
    }
    int minCameraCover(TreeNode* root) {
        //头节点单独处理判断
        if(traversal(root) == 0) { //如果头节点没有被覆盖
            result++;
        }
        return result;
    }
};

贪心算法总结 

文档讲解:代码随想录贪心算法总结

贪心算法一句话:没有套路,多加练习,手动模拟。

贪心算法的题目可以分为: 

题目之间并没有明显的顺序关系,重点还是要多加联系。 

一个系列的结束,标志着另一个系列的开始,动态规划!继续加油💪

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

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

相关文章

美妆网页设计(前端)

目录 一、 网站背景&#xff1a; 1、 背景介绍 2、 项目意义 二、 系统设计&#xff1a; 1.系统目标 2.系统功能结构 3.开发环境 三、 开发实现 1、导航栏 2、轮播效果效果 3、下拉菜单效果 4、模态框 遇到的问题及解决办法 五、 总结&#xff1a; 网站背景&…

【LabVIEW学习篇 - 5】:数据类型——数值、字符串

文章目录 数值枚举下拉列表控件 字符串字符串与十六进制截取字符串连接字符串 字符串与数值间的转换字符串转为数值数值转为字符串 数值 如下图所示&#xff0c;各种数值型数据的不同之处在于存储和表示数据时所使用的位置不同。 浮点型 整型 在LabVIEW中&#xff0c;想要改…

Android计算器界面的设计——表格布局TableLayout实操

目录 任务目标任务分析任务实施 任务目标 使用TextView、Button等实现一个计算器界面&#xff0c;界面如图1所示。 图1 计算器界面效果图 任务分析 界面整体使用表格布局&#xff0c;第一行使用一个TextView控件&#xff0c;横跨4列&#xff0c;中间4行4列&#xff0c;最后一…

Mysql笔记-v2

零、 help、\h、? 调出帮助 mysql> \hFor information about MySQL products and services, visit:http://www.mysql.com/ For developer information, including the MySQL Reference Manual, visit:http://dev.mysql.com/ To buy MySQL Enterprise support, training, …

EAI四个层次服务-系统架构师(二十六)

1、&#xff08;重点&#xff09;系统应用集成提供了4个不同层次服务&#xff0c;最上层服务是&#xff08;&#xff09;服务。 解析: EAI&#xff08;Enterprise Application Integration&#xff09;系统应用集成&#xff0c;相关概念。 实施EAI必须保证&#xff1a;应用程…

OS Copilot测评-CSDN

登录控制台 安装插件 sudo yum install -y os-copilot效果如下 配置 AccessKey ID 与 AccessKey Secret 注意安全&#xff0c;使用完成后&#xff0c;别忘了去控制台删除&#xff0c;一般情况使用子Key就可以 检测是否可用 co hi实际操作(当前为官方案例请求) 实操1&…

分区Partition

理解Partition 向量检索服务DashVector的Collection具有分区&#xff08;Partition&#xff09;的能力&#xff0c;同一个Collection下的Doc可通过不同的Partition进行物理和逻辑上的分区。各种Doc操作&#xff08;如插入Doc、检索Doc等&#xff09;若指定Partition&#xff0…

超好用的傲软录屏下载和解锁版安装教程 (专业好用的桌面录屏软件)

录屏系列软件安装目录 一、ZD屏幕录像机解锁版下载及安装教程 (一款小巧的轻量级屏幕录像工具) 二、班迪录屏Bandicam v7解锁版安装教程&#xff08;高清录屏软件&#xff09; 三、Mirillis Action v4 解锁版安装教程(专业高清屏幕录像软件) 四、Aiseesoft Screen Recorder…

react-类组件1

类组件&#xff1a; import { Component } from "react";class App extends Component {constructor() {super();this.state {message: "xxxxx",};}render() {return (<div><div>{this.state.message}</div></div>);} }export d…

如 何 避 开 职 场 雷 区

01 管理好自己的情绪 在职场中切忌过于情绪化&#xff0c;学会管理好自己的情绪是一个职场人必备的技能之一。坏情绪并不会帮助你解决任何问题&#xff0c;过多的抱怨&#xff0c;只会使你成为负能量的传播者。 在职场中&#xff0c;需要做的是管理好自己的情绪&#xff0c;积…

Python--并发编程--协程

概念 协程是轻量级的线程&#xff0c;它是程序员管理的并发机制&#xff0c;使得在一个线程中程序可以在多个函数之间交替运行。 Python中主要通过asyncio模块实现协程。 协程函数 用async修饰的函数 import asyncio# func为协程函数 async def func():await asyncio.slee…

【C语言】extern 关键字详解

在C语言中&#xff0c;extern关键字用于声明一个变量或函数是定义在另一个文件中的。它使得在多个文件之间共享变量或函数成为可能。extern关键字常见于大型项目中&#xff0c;通常用于声明全局变量或函数&#xff0c;这些变量或函数的定义位于其他文件中。 基本用法 变量声明…

[极客大挑战 2019]RCE ME

[极客大挑战 2019]RCE ME <?php error_reporting(0); if(isset($_GET[code])){$code$_GET[code];if(strlen($code)>40){die("This is too Long.");}if(preg_match("/[A-Za-z0-9]/",$code)){die("NO.");}eval($code); } else{highlight_f…

考CISP,不要踩坑的几点建议

当你立志要在信息安全领域闯出一片天&#xff0c;可能多少都会听行内人说&#xff0c;搞本CISP。但这个认证究竟该怎么拿&#xff1f;需要培训吗&#xff1f;培训又是怎么一回事&#xff1f;价格如何&#xff1f;还有&#xff0c;什么时候开始准备最好&#xff1f;这些问题可能…

简易Qt串口助手

界面显示如下 关于串口类 初始化 设置串口号 设置波特率 打开串口 发送按钮功能实现 接收数据显示在控件中 关闭串口

FFmpeg 实现从麦克风获取流并通过RTMP推流

使用FFmpeg库实现从麦克风获取流并通过RTMP推流&#xff0c;FFmpeg版本为4.4.2-0。RTMP服务器使用的是SRS&#xff0c;我这边是跑在Ubuntu上的&#xff0c;最好是关闭掉系统防火墙。拉流端使用VLC。如果想要降低延时&#xff0c;请看我另外一篇博客&#xff0c;里面有说降低延时…

【密码学基础】基于LWE(Learning with Errors)的全同态加密方案

学习资源&#xff1a; 全同态加密I&#xff1a;理论与基础&#xff08;上海交通大学 郁昱老师&#xff09; 全同态加密II&#xff1a;全同态加密的理论与构造&#xff08;Xiang Xie老师&#xff09; 现在第二代&#xff08;如BGV和BFV&#xff09;和第三代全同态加密方案都是基…

数据集 | 人脸公开数据集的介绍及下载地址

本文介绍了人脸相关算法的数据集。 1.人脸数据集详情 1.1.Labeled Faces in the Wild (LFW) 论文 下载地址&#xff1a;LFW Face Database : Main (umass.edu) 是目前人脸识别的常用测试集&#xff0c;其中提供的人脸图片均来源于生活中的自然场景&#xff0c;因此识别难度会…

表情包原理

https://unicode.org/Public/emoji/12.1/emoji-zwj-sequences.txt emoji 编码规则介绍_emoji编码-CSDN博客 UTS #51: Unicode Emoji C UTF-8编解码-CSDN博客 创作不易&#xff0c;小小的支持一下吧&#xff01;

数据结构练习

1. 快速排序的非递归是通过栈来实现的&#xff0c;则前序与层次可以通过控制入栈的顺序来实现&#xff0c;因为递归是会一直开辟栈区空间&#xff0c;所以非递归的实现只需要一个栈的大小&#xff0c;而这个大小是小于递归所要的&#xff0c; 非递归与递归的时间复杂度是一样的…