贪心算法|968.监控二叉树

力扣题目链接

class Solution {
private:
    int result;
    int traversal(TreeNode* cur) {

        // 空节点,该节点有覆盖
        if (cur == NULL) return 2;

        int left = traversal(cur->left);    // 左
        int right = traversal(cur->right);  // 右

        // 情况1
        // 左右节点都有覆盖
        if (left == 2 && right == 2) return 0;

        // 情况2
        // 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
        // left == 1 && right == 2 左节点有摄像头,右节点有覆盖
        // left == 2 && right == 1 左节点有覆盖,右节点有摄像头
        // left == 1 && right == 1 左右节点都有摄像头
        // 其他情况前段代码均已覆盖
        if (left == 1 || right == 1) return 2;

        // 以上代码我没有使用else,主要是为了把各个分支条件展现出来,这样代码有助于读者理解
        // 这个 return -1 逻辑不会走到这里。
        return -1;
    }

public:
    int minCameraCover(TreeNode* root) {
        result = 0;
        // 情况4
        if (traversal(root) == 0) { // root 无覆盖
            result++;
        }
        return result;
    }
};

这题是困难题,需要多次看理解哦!

代码随想录 (programmercarl.com)

思路

这道题目首先要想,如何放置,才能让摄像头最小的呢?

从题目中示例,其实可以得到启发,我们发现题目示例中的摄像头都没有放在叶子节点上!

这是很重要的一个线索,摄像头可以覆盖上中下三层,如果把摄像头放在叶子节点上,就浪费的一层的覆盖。

所以把摄像头放在叶子节点的父节点位置,才能充分利用摄像头的覆盖面积。

那么有同学可能问了,为什么不从头结点开始看起呢,为啥要从叶子节点看呢?

因为头结点放不放摄像头也就省下一个摄像头, 叶子节点放不放摄像头省下了的摄像头数量是指数阶别的。

所以我们要从下往上看,局部最优:让叶子节点的父节点安摄像头,所用摄像头最少,整体最优:全部摄像头数量所用最少!

局部最优推出全局最优,找不出反例,那么就按照贪心来!

此时,大体思路就是从低到上,先给叶子节点父节点放个摄像头,然后隔两个节点放一个摄像头,直至到二叉树头结点。

此时这道题目还有两个难点:

  1. 二叉树的遍历
  2. 如何隔两个节点放一个摄像头

#确定遍历顺序

在二叉树中如何从低向上推导呢?

可以使用后序遍历也就是左右中的顺序,这样就可以在回溯的过程中从下到上进行推导了。

后序遍历代码如下:

int traversal(TreeNode* cur) {

    // 空节点,该节点有覆盖
    if (终止条件) return ;

    int left = traversal(cur->left);    // 左
    int right = traversal(cur->right);  // 右

    逻辑处理                            // 中
    return ;
}

注意在以上代码中我们取了左孩子的返回值,右孩子的返回值,即left 和 right, 以后推导中间节点的状态

#如何隔两个节点放一个摄像头

此时需要状态转移的公式,大家不要和动态的状态转移公式混到一起,本题状态转移没有择优的过程,就是单纯的状态转移!

来看看这个状态应该如何转移,先来看看每个节点可能有几种状态:

有如下三种:

  • 该节点无覆盖
  • 本节点有摄像头
  • 本节点有覆盖

我们分别有三个数字来表示:

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

大家应该找不出第四个节点的状态了。

一些同学可能会想有没有第四种状态:本节点无摄像头,其实无摄像头就是 无覆盖 或者 有覆盖的状态,所以一共还是三个状态。

因为在遍历树的过程中,就会遇到空节点,那么问题来了,空节点究竟是哪一种状态呢? 空节点表示无覆盖? 表示有摄像头?还是有覆盖呢?

回归本质,为了让摄像头数量最少,我们要尽量让叶子节点的父节点安装摄像头,这样才能摄像头的数量最少。

那么空节点不能是无覆盖的状态,这样叶子节点就要放摄像头了,空节点也不能是有摄像头的状态,这样叶子节点的父节点就没有必要放摄像头了,而是可以把摄像头放在叶子节点的爷爷节点上。

所以空节点的状态只能是有覆盖,这样就可以在叶子节点的父节点放摄像头了

接下来就是递推关系。

那么递归的终止条件应该是遇到了空节点,此时应该返回2(有覆盖),原因上面已经解释过了。

代码如下:

// 空节点,该节点有覆盖
if (cur == NULL) return 2;

递归的函数,以及终止条件已经确定了,再来看单层逻辑处理。

主要有如下四类情况:

  • 情况1:左右节点都有覆盖

左孩子有覆盖,右孩子有覆盖,那么此时中间节点应该就是无覆盖的状态了。

如图:

968.监控二叉树2

代码如下:

// 左右节点都有覆盖
if (left == 2 && right == 2) return 0;

  • 情况2:左右节点至少有一个无覆盖的情况

如果是以下情况,则中间节点(父节点)应该放摄像头:

  • left == 0 && right == 0 左右节点无覆盖
  • left == 1 && right == 0 左节点有摄像头,右节点无覆盖
  • left == 0 && right == 1 左节点有无覆盖,右节点摄像头
  • left == 0 && right == 2 左节点无覆盖,右节点覆盖
  • left == 2 && right == 0 左节点覆盖,右节点无覆盖

这个不难理解,毕竟有一个孩子没有覆盖,父节点就应该放摄像头。

此时摄像头的数量要加一,并且return 1,代表中间节点放摄像头。

代码如下:

if (left == 0 || right == 0) {
    result++;
    return 1;
}

  • 情况3:左右节点至少有一个有摄像头

如果是以下情况,其实就是 左右孩子节点有一个有摄像头了,那么其父节点就应该是2(覆盖的状态)

  • left == 1 && right == 2 左节点有摄像头,右节点有覆盖
  • left == 2 && right == 1 左节点有覆盖,右节点有摄像头
  • left == 1 && right == 1 左右节点都有摄像头

代码如下:

if (left == 1 || right == 1) return 2;

1

从这个代码中,可以看出,如果left == 1, right == 0 怎么办?其实这种条件在情况2中已经判断过了,如图:

968.监控二叉树1

这种情况也是大多数同学容易迷惑的情况。

  1. 情况4:头结点没有覆盖

以上都处理完了,递归结束之后,可能头结点 还有一个无覆盖的情况,如图:

968.监控二叉树3

所以递归结束之后,还要判断根节点,如果没有覆盖,result++,代码如下:

int minCameraCover(TreeNode* root) {
    result = 0;
    if (traversal(root) == 0) { // root 无覆盖
        result++;
    }
    return result;
}

这题自己还没理解,消化不了呜呜呜 贪心算法,二叉树与贪心的结合,有点难...... LeetCode:968.监督二叉树_哔哩哔哩_bilibili

不过思路理解了,怎样放摄像头~

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

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

相关文章

GPT与Python结合应用于遥感降水数据处理、ERA5大气再分析数据的统计分析、干旱监测及风能和太阳能资源评估等大气科学关键场景

如何结合最新AI模型与Python技术处理和分析气候数据。介绍包括GPT-4等先进AI工具,旨在帮助大家掌握这些工具的功能及应用范围。 内容覆盖使用GPT处理数据、生成论文摘要、文献综述、技术方法分析等实战案例,使大家能够将AI技术广泛应用于科研工作。特别关…

摩天大楼为什么建不成

小小学校让搞什么生活中的数学,推荐主题各种高大上,而我独爱简单,昨天讲了大概,仅从电梯开销说明摩天大楼为什么不能无限高,今天作文记下。不过最终,我还是没有选择这个题目,而是帮助小小讲区块…

【Git教程】(十)版本库之间的依赖 —— 项目与子模块之间的依赖、与子树之间的依赖 ~

Git教程 版本库之间的依赖 1️⃣ 与子模块之间的依赖2️⃣ 与子树之间的依赖🌾 总结 在 Git 中,版本库是发行单位,代表的是一个版本,而分支或标签则只能被创建在版本库这个整体中。如果一个项目中包含了若干个子项目,…

修复开始菜单消失或不能工作的几种方法,总有一种适合你

如果Windows开始菜单消失或按Windows键时无法打开,请修复Windows 11或Windows 10 PC上的一些系统组件,使菜单重新工作。下面是如何做到这一点。 作为基本修复,请重新启动Windows 11或Windows 10 PC,看看是否解决了问题。如果没有,请使用以下故障排除方法。 使任务栏可见…

MATLAB如何分析根轨迹(rlocus)

根轨迹分析是一种图形化方法,用于研究闭环极点随系统参数(通常是反馈增益)变化时的移动情况。 绘制根轨迹目的就是改变系统的闭环极点,使得系统由不稳定变为稳定或者使得稳定的系统变得更加稳定。 主导极点 主导极点就是离虚轴最近的闭环极…

【通信原理笔记】【三】——3.7 频分复用

文章目录 前言一、时分复用(TDM)二、频分复用(FDM)总结 前言 现在我们学习了几种调制模拟基带信号的方法,这些调制方法可以将基带信号搬移到频带进行传输。那么如果采用不同的载波频率把多个基带信号搬移到不同的频带…

京东详情比价接口优惠券(2)

京东详情API接口在电子商务中的应用与作用性体现在多个方面,对于电商平台、商家以及用户都带来了显著的价值。 首先,从应用的角度来看,京东详情API接口为开发者提供了一整套丰富的功能和工具,使他们能够轻松地与京东平台进行交互。…

从数据中台到上层应用全景架构示例

一、前言 对于大型企业而言,数据已经成为基本的生产资料,但是有很多公司还是值关心上层应用,而忽略了数据的治理,从而并不能很好的发挥公司的数据资产效益。比如博主自己是做后端的,主要是做应用层,也就是…

【研发效能·创享大会-嗨享技术轰趴】-IDCF五周年专场

一、这是一场创新分享局! 来吧,朋友们! 参加一场包含AIGC、BizDevOps、ToB产品管理、B端产品运营、平台工程、研发效能、研发度量、职业画布、DevOps国标解读的研发效能创享大会,会有哪些收益呢? 知识更新与技能提升:…

2024妈妈杯mathorcup数学建模C题 物流网络分拣中心货量预测及人员排班

一、数据预处理 数据清洗是指对数据进行清洗和整理,包括删除无效数据、缺失值填充、异常值检测和处理等。数据转换是指对数据进行转换和变换,包括数据缩放、数据归一化、数据标准化等。数据整理是指对数据进行整理和归纳,包括数据分组、数据聚…

记一次http访问超时服务器端调试

问题:http访问服务器时没有返回,没有超时,一直在阻塞 处理过程:telnet端口能连上,服务端程序也不存在处理时间过长的情况。 说明tcp连接没问题。推测是客户端连接后再发起请求,服务端阻塞了。因为很多客户…

2024-4-12-实战:商城首页(下)

个人主页:学习前端的小z 个人专栏:HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结,欢迎大家在评论区交流讨论! 文章目录 作业小结 作业 .bg-backward {width: 60px; height: 60px;background: url(..…

Java集合(一)Map(1)

Map HashMap和HashTable区别 线程是否安全:HashMap线程不安全,HashTable线程安全。因为HashTable内部的方法都经过了synchronized关键字修饰。 HashMap线程不安全例子:如果两个线程都要往HashMap中插入数据,但是发生哈希冲突&…

【爬虫+数据清洗+可视化分析】python文本挖掘“狂飙“的哔哩哔哩评论

一、背景介绍 2023年《狂飙》这部热播剧引发全民追剧,不仅全员演技在线,更是符合反黑主旋律,因此创下多个收视率记录! 基于此热门事件,我用python抓取了B站上千条评论,并进行可视化舆情分析。 二、爬虫代…

Aconda教程

1.创建Aconda的虚拟环境 conda create -n 虚拟环境名字2.查看Conda有哪些虚拟环境 conda env list3.激活Conda的虚拟环境 conda activate 虚拟环境名4.查看conda的镜像源 conda config --show 5.conda安装cpu版本的pytorch pip3 install torch torchvision torchaudio 6.…

YOLOv8绝缘子边缘破损检测系统(可以从图片、视频和摄像头三种方式检测)

可检测图片和视频当中出现的绝缘子和绝缘子边缘是否出现破损,以及自动开启摄像头,进行绝缘子检测。基于最新的YOLO-v8训练的绝缘子检测模型和完整的python代码以及绝缘子的训练数据,下载后即可运行。(效果视频:YOLOv8绝…

【机器学习】Logistic与Softmax回归详解

在深入探讨机器学习的核心概念之前,我们首先需要理解机器学习在当今世界的作用。机器学习,作为人工智能的一个重要分支,已经渗透到我们生活的方方面面,从智能推荐系统到自动驾驶汽车,再到医学影像的分析。它能够从大量…

【linux深入剖析】动态库的使用(续) | 动静态库的链接

🍁你好,我是 RO-BERRY 📗 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 目录 回顾1. 打包库的使用2. 动…

JavaWeb--JavaScript-事件绑定/BOM/DOM编程

目录 1. 事件绑定 1.1. 什么是事件 1.2. 常见事件 1.3. 事件的绑定 1.3.1. 属性绑定 1.3.2. DOM编程绑定 1.4. 事件的触发 1.4.1. 行为触发 1.4.2. DOM编程触发 2. BOM 编程 2.1. 什么是 BOM 2.2. window对象的常见属性(了解) 2.3. window对象的常见方法(了解) 2…

如何准备2024年汉字小达人:18道历年考题示例和解析、备考提醒

现在距离2024年第11届汉字小达人比赛还有六个多月的时间,如何利用这段时间有条不紊地备考呢?我的建议是两手准备:①把小学1-5年级的语文课本上的知识点熟悉,重点是字、词、成语、古诗。阅读理解不需要。②把历年真题刷刷熟&#x…