代码随想录二刷day37 | 贪心 之 738.单调递增的数字 968.监控二叉树

news2024/11/19 23:41:21

day37

      • 738.单调递增的数字
      • 968.监控二叉树
        • 确定遍历顺序
        • 如何隔两个节点放一个摄像头
          • 情况1:左右节点都有覆盖
          • 情况2:左右节点至少有一个无覆盖的情况
          • 情况3:左右节点至少有一个有摄像头
          • 情况4:头结点没有覆盖

738.单调递增的数字

题目链接
解题思路:
例如:98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。

这一点如果想清楚了,这道题就好办了。

从前向后遍历的话,遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]减一,但此时如果strNum[i - 1]减一了,可能又小于strNum[i - 2]

这么说有点抽象,举个例子,数字:332,从前向后遍历的话,那么就把变成了329,此时2又小于了第一位的3了,真正的结果应该是299。

那么从后向前遍历,就可以重复利用上次比较得出的结果了,从后向前遍历332的数值变化为:332 -> 329 -> 299

确定了遍历顺序之后,那么此时局部最优就可以推出全局,找不出反例,试试贪心。

C++代码如下:

class Solution {
public:
    int monotoneIncreasingDigits(int N) {
        string strNum = to_string(N);
        // flag用来标记赋值9从哪里开始
        // 设置为这个默认值,为了防止第二个for循环在flag没有被赋值的情况下执行
        int flag = strNum.size();
        for (int i = strNum.size() - 1; i > 0; i--) {
            if (strNum[i - 1] > strNum[i] ) {
                flag = i;
                strNum[i - 1]--;
            }
        }
        for (int i = flag; i < strNum.size(); i++) {
            strNum[i] = '9';
        }
        return stoi(strNum);
    }
};

968.监控二叉树

题目链接
解题思路:
局部最优:让叶子节点的父节点安摄像头,所用摄像头最少,整体最优:全部摄像头数量所用最少!
这道题目还有两个难点:

  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:左右节点都有覆盖

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

如图:
在这里插入图片描述
代码如下:

// 左右节点都有覆盖
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;

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

968.监控二叉树1

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

情况4:头结点没有覆盖

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

968.监控二叉树3
所以递归结束之后,还要判断根节点,如果没有覆盖,result++,代码如下:

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

以上四种情况我们分析完了,代码也差不多了,整体代码如下:

(以下我的代码注释很详细,为了把情况说清楚,特别把每种情况列出来。)

C++代码如下:

// 版本一
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;
    }
};

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

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

相关文章

H5学习(四)-- 常用属性

文章目录 一、字体设置字体格式设置字体大小设置字体粗细设置字体样式设置字体颜色 二、 文本设置文本对齐方式设置文本装饰方式设置文本缩进设置文本行高 三、背景设置背景颜色设置背景图片设置背景平铺设置背景位置设置背景尺寸 四、圆角矩形五、元素的显示模式块级元素行内元…

解决win10开机卡顿、配置很高但是玩游戏卡顿掉帧等问题

解决win10开机卡顿、配置很高但是玩游戏卡顿掉帧等问题 最近组装了一台高配置的新电脑&#xff0c;装好了各种驱动、软件等。发现系统开机后卡顿一分钟左右&#xff08;加载应用配置等&#xff09;&#xff0c;但是我的系统启动项明明就没多少&#xff0c;不应该是这样的情况&…

最优化--梯度下降法--牛顿法(详解)

目录 梯度下降法 梯度下降法 步骤 牛顿法 牛顿法的基本思想 牛顿法的优缺点 作用 梯度下降法 梯度下降法&#xff08;Gradient Descent&#xff09;是一种常用的优化算法&#xff0c;用于求解函数的最小值或最大值。它通过迭代的方式&#xff0c;不断更新参数的取值&…

cmd获取apk签名hash、获取apk是否启用了V1\V2\V3\V4签名

1、从APK中获取签名hash keytool -printcert -jarfile apk路径 2、获取apk是否启用了V2\V3\V4签名 //在android sdk 目录&#xff0c;如 xxx\Sdk\build-tools\34.0.0 里&#xff0c;执行apksigner.bat verify -v apk路径

小白到运维工程师自学之路 第四十三集 (mariadb读写分离)

一、读写分离的优点 1. 负载均衡&#xff1a;将读操作分散到多个从库上&#xff0c;可以有效地分担主库的读负载&#xff0c;提高系统的 并发处理能力。 2. 提高读性能&#xff1a;从库可以通过增加硬件资源或者优化查询语句等方式来提高读操作的性 能&#xff0c;从而提升…

为什么用了代理ip访问网站还是被限制了

随着网络的发展和应用的普及&#xff0c;越来越多的用户开始使用代理ip来访问网站。代理ip可以隐藏真实IP地址&#xff0c;提供匿名性和访问自由&#xff0c;但有时候使用代理ip仍然会导致被禁止访问网站的情况发生。下面就让我们来分析一下吧。 代理ip被网站识别 一些网站通过…

从零详细地梳理一个完整的 LLM 训练流程

深度学习自然语言处理 分享知乎&#xff1a;何枝 在这篇文章中&#xff0c;我们将尽可能详细地梳理一个完整的 LLM 训练流程。包括模型预训练&#xff08;Pretrain&#xff09;、Tokenizer 训练、指令微调&#xff08;Instruction Tuning&#xff09;等环节。 文末进群&#xf…

两种特定网络环境下,如何实现外网SSH访问内网LINUX主机?

目前&#xff0c;大多数网友的网络环境分为两种&#xff0c;一种是没有公网IP&#xff0c;一种是动态公网IP环境。今天跟大家分享一下在这两种特定网络环境下&#xff0c;如何通过快解析内网穿透&#xff0c;实现外网SSH访问内网LINUX。 1.动态公网IP环境。路由器分配的是动态…

深入了解 KaiwuDB 负载行为数据采集

KAP 基于数据库系统内部反馈的各项数据指标&#xff0c;可帮助用户全面掌握 KaiwuDB 集群的整体运行情况&#xff0c;实时监测集群相关性能&#xff0c;可提供整体资源和集群状态角度的系统监控。 除此之外&#xff0c;KaiwuDB 数据库内部开发实现基于负载业务的行为数据采集功…

(九)栅格数据的空间分析——表面分析①

生成等值线 文章目录 生成等值线 1.等值线2.等值线质量3.控制等值线质量3.1对数据进行平滑处理3.2调整起始等值线 4.生成等值线4.1焦点统计4.2生成等值线 1.等值线 沿着特定等值线的折线 (polyline) 可识别出值相同的位置。等值线也是一种呈现表面的有效形式&#xff0c;因为它…

jmeter 报此错误 \report‘ as folder is not empty

jmeter 报此错误 \report’ as folder is not empty 解决方案 出现此错误的原因试因为同一个界面出现同样的文件&#xff0c;只要把文件删除&#xff0c;重新执行此命令即可。 删除文件框住得report和result.jtl 即可 执行成功

计算机图形学 3D渲染 笔记(一)

1 坐标系 大多数计算机屏幕采用的坐标系是以左上角为原点&#xff0c;水平&#xff08;右&#xff09;为x轴&#xff0c;纵向&#xff08;下&#xff09;为y轴3D图形学习中通常使用另一种坐标系&#xff0c; 即 正中心为原点&#xff0c;水平&#xff08;右&#xff09;为x轴&…

【算法题解】44. N 叉树的前序遍历(递归 + 迭代)

这是一道 简单 题 https://leetcode.cn/problems/n-ary-tree-preorder-traversal/ 题目 给定一个 n 叉树的根节点 root &#xff0c;返回 其节点值的 前序遍历 。 n 叉树 在输入中按层序遍历进行序列化表示&#xff0c;每组子节点由空值 null 分隔&#xff08;请参见示例&…

Golang源码探究——从Go程序的入口到GMP模型

在大多数的编程语言中&#xff0c;main函数都是用户程序的入口函数&#xff0c;go中也是如此。那么main.main是整个程序的入口吗, 肯定不是&#xff0c;因为go程序依赖于runtime&#xff0c;在程序的初始阶段需要初始化运行时&#xff0c;之后才会运行到用户的main函数&#xf…

【话题达人】做开发时遇到过无理的需求吗?面对这些无理需求你是怎么做的?

导读 工作过程中难免遇见一些“神奇的甲方”&#xff0c;他们总是会给你提出一些匪夷所思甚至无厘头的需求。你是否也有这样的经历&#xff0c;面对这样“无理的需求”你又是怎么做的呢&#xff1f; 面对这些无理需求时你是怎么做的&#xff1f; 首先深入了解需求&#xff0…

C++一键安装工具(vcpkg)

0. 简介 相较于python而言&#xff0c;C因为其复杂的环境安装一直受到很多人的诟病&#xff0c;比如说一个pcl的安装就需要有很多操作步骤。译过程仍然复杂和多样化。当了解了这些还不够&#xff0c;我们还需要考虑预先编译出哪种类型的开源库程序。比如&#xff1a;Debug还是…

快速掌握MongoDB数据库(入门一条龙)

目录 一、介绍 二、安装指导 2.1 下载 2.2 安装注意事项 2.3 配置环境变量 2.4 校验是否配置成功 2.5 启动服务器 2.6 打开客户端 2.7 退出 2.8 修改参数配置 2.9 设置开启自启动服务 三、MongoDB基本操作 3.1 基本概念 3.2 基本命令 3.3 数据库的crud命令 四、…

七、云尚办公-Activiti入门

云尚办公系统&#xff1a;Activiti入门 B站直达【为尚硅谷点赞】: https://www.bilibili.com/video/BV1Ya411S7aT 本博文以课程相关为主发布&#xff0c;并且融入了自己的一些看法以及对学习过程中遇见的问题给出相关的解决方法。一起学习一起进步&#xff01;&#xff01;&am…

《C++高级编程》读书笔记(十三:C++ I/O揭秘)

1、参考引用 C高级编程&#xff08;第4版&#xff0c;C17标准&#xff09;马克葛瑞格尔 2、建议先看《21天学通C》 这本书入门&#xff0c;笔记链接如下 21天学通C读书笔记&#xff08;文章链接汇总&#xff09; 1. 使用流 1.1 流的含义 C 中预定义的流 缓冲的流和非缓冲的流…

SpringBoot:配置Jetty容器

&#x1f468;‍&#x1f393;作者&#xff1a;bug菌 ✏️博客&#xff1a; CSDN、 掘金、 infoQ、 51CTO等 &#x1f389;简介&#xff1a;CSDN、 掘金等社区优质创作者&#xff0c;全网合计7w粉&#xff0c;对一切技术都感兴趣&#xff0c;重心偏Java方向&#xff0c;目前运营…