算法学习打卡day36| 738.单调递增的数字、 968.监控二叉树、贪心算法阶段学习总结

news2025/7/27 19:24:52

738.单调递增的数字

力扣题目链接
题目描述:
当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。

给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。
示例 1:
输入: n = 10
输出: 9

示例 2:
输入: n = 1234
输出: 1234
示例 3:
输入: n = 332
输出: 299

思路:

  • 暴力方法很好想,就是倒序遍历,然后判断每个数字是否符合条件就行了,但是提交后会超时😄。
  • 细想一下,如果每次只是–1,然后再去判断的话,那么在上一个数字不符合条件时,那个位置之前做的所有判断就白做了。
  • 那么能不能把之前的利用起来呢? 当然可以!我们把数字用库函数转换为字符串,然后去逐字符倒序比较(注意是倒序,不能是正序),遇到s[i - 1] > s[i] 的情况就让s[i - 1] - 1,然后让s[i]之后色所有数字都变为9,只有这样才能保证一直符合条件也能保证是最大值(而不是把s[i - 1]减到s[i] - 1,然后s[i]后面都不动,很显然只让s[i - 1] - 1然后后面所有值变为9更大一些,本题的需求是求最大值!)
  • 为什么不是正序遍历?
    • 因为正序遍历后,假如此时s[i - 1]s[i]是符合递增条件的,那后面万一s[i + 1] < s[i]的话,必须让s[i] - 1,那么此时可能s[i - 1] > s[i]了,全面的又不符合条件了,唯有倒序遍历,后面的值一直比前面值大。

代码实现:

int monotoneIncreasingDigits(int n) {
        if (n < 10) return n;
        string s = to_string(n);
        int flag = s.size();
        for (int i = s.size() - 1; i > 0; --i) {
            if (s[i] < s[i - 1]) {
                s[i - 1]--;
                flag = i;
            }
        }
        //为了减少循环里多做的重复修改动作,直接设置一个flag位,在退出后,统一修改
        for (int j = flag; j < s.size(); ++j) {
            s[j] = '9';
        }
        return stoi(s);
    }

968.监控二叉树

力扣题目链接
题目描述:
给定一个二叉树,我们在树的节点上安装摄像头。

节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。

计算监控树的所有节点所需的最小摄像头数量。

示例 1:
在这里插入图片描述

输入:[0,0,null,0,0]
输出:1
解释:如图所示,一台摄像头足以监控所有节点。

思路:

  • 这道题是贪心 + 二叉树的结合,在哪个节点放摄像机才能让摄像机数量整体保证最小?那根据贪心的思想肯定是放中间节点最好,因为其可以辐射两个子节点和一个父节点,叶子节点肯定不能放,因为它只能辐射自己的父节点,不可能让我们的总量最小。
  • 那根据二叉树的做题思路,先判断用哪种遍历方式,因为我们不在叶子节点放摄像头,那么肯定需要判断左右子树的结果,是空还是叶子节点还是非叶子节点,肯定是左 > 右 > 中了,后序遍历走起!
  • 决定了遍历方式后,就要决定返回值,参数、函数退出逻辑以及单层递归逻辑,递归三部曲
    • 函数参数:参数肯定是树节点root,和传出参数count表示摄像机个数。
    • 返回值:由于我们需要根据左右子树的函数返回值来判断当前节点是否需要安装摄像头,那么返回值肯定是左右子节点的状态了,状态无非是:安装或者未安装,但是未安装其实是有两种状态的,如果子节点安装了,那父节点就不必要安装了,此时是被覆盖而不用安装,还有一种就是没有被覆盖也没有安装的(比如叶子节点)所以,其实一共三种状态:未覆盖、安装、被覆盖,我们分别用0,1,2来表示,分别需要有不同的应对处理方式。
    • 函数退出条件:
      • 当遇到空节点时,返回2,为什么?因为空节点是不用管他的,就当它被覆盖了,但是肯定不能是0和1吧?
      • 当遇到叶子节时,返回0,这个很好理解,叶子节点就要被它的父节点去覆盖。
      • 当遇到非叶子节点,直接交给递归。(这一步就属于单步处理逻辑了,因为不用退出我们需要处理它的返回值)
    • 单步处理逻辑:分别递归左右子节点,然后取其返回值进行比较
      • left == 0 || right == 0)时,我们需要安装摄像头,因为子节点未覆盖,直接count++,然后返回 1。
      • left == 1 || right == 1时,我们不需要安装摄像头了,因为子节点安装了,但是当前节点被覆盖了,所以返回 2。
      • 剩下就是等于 2 的情况了,不用单独判断,直接返回 0。为啥? 因为子节点都是被覆盖,而当前节点最好交给父节点去判断,如果当前节点安装了摄像头就和叶子节点一个逻辑了,相当于只辐射了父节点,两个子节点人家已经被别的节点覆盖了!
    • 另外注意根节点的判断,因为没人能处理root的返回值,只能交给调用递归函数的主函数了!
  • 自己第一次的做题思路:想到了后序遍历,也想到了叶子节点不能放摄像头,就是没想到返回值有三种状态,只是返回了true或者false,安装了就返回true,未安装就返回false,然后处理返回值的时候,只要左右返回值有true就当前节点就返回false,因为是子节点安装了嘛,我肯定被辐射到了!左右节点返回值都是false,我自己就安装一个,其实这也是错误的地方,因为无法判断两个子节点是因为被覆盖而返回false,还是因为未被覆盖而返回的false

代码实现:

int traverse(TreeNode* root, int& count) {
        if (root == nullptr) return 2;
        if (!root->left && !root->right) return 0;
        int left =  traverse(root->left, count);
        int right = traverse(root->right, count);
        if (left == 0 || right == 0) {
            count++;
            return 1;
        }
        if (left == 1 || right == 1)    return 2;
        return 0;
    } 
    int minCameraCover(TreeNode* root) {
        int count = 0;
        if (traverse(root, count) == 0) {
            count++;
        }
        return count;
    }

贪心算法阶段学习总结

  • 学了一周贪心,除了覆盖问题有点套路外,其实题还是懵懵懂懂的,感觉做出来的题和贪心没啥大关系,哎,多练吧😑
  • 下面做个总结
    • 什么是贪心?
      • 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。
      • 大概分为四个步骤分析问题:
        1. 将问题分解为若干个子问题
        2. 找出适合的贪心策略
        3. 求解每一个子问题的最优解
        4. 将局部最优解堆叠成全局最优解
      • 这个很虚无缥缈,一般情况怎么拆解子问题都不好想,凭感觉如果觉得可以通过局部最优实现全局最优,且列举不出来反例,就可以试试贪心算法,可能做的题不多,体会不深很深😄。
    • 简单题:
      • 分发饼干:这道题就是对胃口数组和饼干数组排序,然后尽量把小饼干分给小胃口,大饼干分给大胃口,注意只用一个循环的写法,怎么写?
      • K次取反后最大化的数组和:这道题要对数组根据绝对值排序,然后每次先反转负数,等都反转为正数后,取最小值重复反转就可以保证整体值最大,贪起来。
      • 贪心算法:柠檬水找零, 这个题也很简单,就是把三种金额的币分别存起来,遇到20优先找10和5,没有10再找三个5,其他没有什么难度。
    • 中等题:
      • 单调递增的数字:就是上面做的第一道题,数字转换为字符串的处理思路,可以省去取余和除法操作!然后遇到不符合情况-1而不是减到比后一位少1
      • 股票题:股票题最好用动态规划做,就只有一个题用贪心,性能会好一点,直接拿到相邻两天的股票价格差,取正数相加即可,可以在遍历的途中就取最值,得结果了,也可以滑动窗口。
      • 区间覆盖问题:
        • 一共是六道题,重叠区间四道题,有:435. 无重叠区间、763.划分字母区间、56. 合并区间、452. 用最少数量的箭引爆气球,除了划分字符串,其他三道题都是套模版,字母区间这道题就是记录每个字母的右边界,然后循环不断更新right,直到i走到right就是一个子序列
        • 还有两道跳跃游戏题 也属于区间问题,跳跃游戏是不断更新自己能走到的最远处,只要最远处包含了数组最后一个元素就返回true,而跳跃游戏2是不仅要道最远处还要使得步数最小,那么就每次先走到第一步能走到的最远处,然后走的途中记录第二步能到的最远处,以便更新,第二部的右界,每次走到了右界,就判断下下一步能不能走到数组结尾,能得话步数+1退出 ,其实感觉和划分字母子区间的思路类似,都是不断更改上界,直到上界遇到某个临界值或者走到上界了要怎么处理。
      • 两个维度权衡问题
        • 分发糖果:先满足左或右边界,再满足另一边
        • 根据身高重建队列:这道题必须先满足身高,然后再根据第二个元素去插入即可,注意这道题的链表实现,涉及到vector扩容问题,还有注意身高相同时要,怎么排序
    • hard题目
      • 加油站:这道题思路很难想,但是实现很简单,就是一个循环,然后不断求出当前剩余油是否是正数,如果是负数,那么起点一定在当前加油站之后。
      • 最大连续子序和:和加油站一个思路,只要出现负数就不要了,从负数下一个点开始算,因为出现负数就会令整体和变小。
      • 摆动序列:这道题就有点难度了,贪心思想贪的点在于找到一段序列让每个坡都只有开头和结束两个点,因为要比较坡度是否一样,就要和前一组之差比较,只要符号不同就算符合条件,pre_diff > 0 && cur_diff < 0 || pre_diff < 0 && cur_diff > 0,但要注意平坡的出现,以及什么时候更新pre_diff
      • 监控二叉树:后序+贪心,注意递归函数返回值的三种状态

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

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

相关文章

JVM虚拟机:通过一个例子解释JVM中栈结构的使用

代码 代码解析 main方法执行&#xff0c;创建栈帧并压栈。 int d8&#xff0c;d为局部变量&#xff0c;是基础类型&#xff0c;它位于虚拟机栈的局部变量表中 然后创建了一个TestDemo的对象&#xff0c;这个对象在堆中&#xff0c;并且这个对象的成员变量&#xff08;day&am…

安防视频监控平台EasyCVR(V.3.4)新功能:告警查询操作步骤

视频集中存储/云存储/视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、智能分析等。AI智能大数据视频分析EasyCVR平台已经广泛应用在工地、工厂、园区、楼…

2024王道考研计算机组成原理——中央处理器

CPU的运算器其实就是进行固定的数据处理&#xff0c;后面讲的CPU主要侧重的是它的控制器功能 运算器的基本结构 左右两边都是16位&#xff0c;因为寄存器可能位于左右两端的一边(源/目的操作数) A、B两端都要接一堆线 通用寄存器 ALU都在运算器当中 从主存来的数据直接放到…

3201. 任务调度

有若干个任务需要在一台机器上运行。 它们之间没有依赖关系&#xff0c;因此可以被按照任意顺序执行。 该机器有两个 CPU 和一个 GPU。 对于每个任务&#xff0c;你可以为它分配不同的硬件资源: 在单个 CPU 上运行。在两个 CPU 上同时运行。在单个 CPU 和 GPU 上同时运行。在两…

RabbitMQ消息队列笔记

目录 docker Java 导包 配置文件 Work Queues 消息堆积 消息生产者发送消息到队列 消息消费者接收消息 Fanout交换机 Direct交换机发送消息 用Java代码创建交换机和队列、绑定 Direct交换机 Direct交换机发送消息 用Java代码创建交换机和队列、绑定 基于注解声明队…

Rust 语言常见的一些概念(上)

目录 1、变量的可变性 常量 隐藏 2、数据类型 2.1 标量类型 整型 浮点型 数值运算 布尔型 字符类型 复合类型 元组类型 数组类型 1、变量的可变性 变量默认是不可改变的&#xff08;immutable&#xff09;。这是 Rust 提供给你的众多优势之一&#xff0c;让你得以…

win32 读写UTF-8格式的文件的方法

1&#xff0c;写入数据 最开始是在写入数据前先写入三个字节 BYTE btHead[] { 0xEF,0xBB,0xBF }; ::WriteFile(hFile, btHead, 3, &dwWrite, 0); ::WriteFile(hFile, str, lstrlen(str)*sizeof(TCHAR), &dwWrite, 0);这样写入后文件样式为&#xff1a; 格式是UTF-8…

基于Python制作一个动物识别小程序

目录 引言研究背景目的与意义 动物识别技术概述基本原理图像处理与特征提取机器学习与深度学习方法 数据集与数据预处理数据收集与构建数据预处理步骤数据增强技术 特征提取与选择基础特征提取方法特征选择与降维 引言 研究背景 动物识别是计算机视觉和模式识别领域的重要研究…

《深入浅出OCR》实战:基于CRNN的文字识别

✨专栏介绍: 经过几个月的精心筹备,本作者推出全新系列《深入浅出OCR》专栏,对标最全OCR教程,具体章节如导图所示,将分别从OCR技术发展、方向、概念、算法、论文、数据集等各种角度展开详细介绍。 💙个人主页: GoAI |💚 公众号: GoAI的学习小屋 | 💛交流群: 7049325…

在python中加载tensorflow-probability模块和numpy模块

目录 操作步骤&#xff1a; 注意&#xff1a; 问题&#xff1a; 解决办法&#xff1a; 操作步骤&#xff1a; 在虚拟环境的文件夹中&#xff0c;找到Scripts文件夹&#xff0c;点击进去&#xff0c;找到地址栏&#xff0c;在地址栏中输入cmd&#xff0c;进入如下界面。 输…

国产数据库兼容过程中涉及的MySQL非严格模式

点击上方蓝字关注我 在国产数据库兼容适配过程中&#xff0c;经常遇到因源数据库是MySQL&#xff0c;迁移至其他国产数据库后&#xff0c;因MySQL端兼容模式有非严格模式&#xff0c;导致适配过程过程中需要做调整。那么&#xff0c;MySQL主要的非严格模式小结如下&#xff1a;…

约会杭州云栖2023:为了无法计算的价值一起努力

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

C++初阶 类和对象(上)

前言&#xff1a;C初阶系列&#xff0c;每一期博主都会使用简单朴素的语言将对应的知识分享给大家&#xff0c;争取让所有人都可以听懂&#xff0c;C初阶系列会持续更新&#xff0c;上学期间将不定时更新&#xff0c;但总会更的 目录 一、什么是面向对象编程 二、什么是类和如…

AST反混淆实战|变种ob混淆还原指南一

关注它&#xff0c;不迷路。 本文章中所有内容仅供学习交流&#xff0c;不可用于任何商业用途和非法用途&#xff0c;否则后果自负&#xff0c;如有侵权&#xff0c;请联系作者立即删除&#xff01; 1.需求 ob混淆是我们最常见的混淆代码&#xff0c;标准的混淆 可以用星…

如何读懂深度学习python项目,以`Multi-label learning from single positive label`为例

Paper : Multi-label learning from single positive label Code 先读一读README.md 可能有意想不到的收获&#xff1b; 实验环境设置要仔细看哦&#xff01; 读论文 如何读论文&#xff0c;Readpaper经典十问 &#xff08;可能在我博客里有写&#xff09; How to read a …

【UE5】如何在UE5.1中创建级联粒子系统

1. 可以先新建一个actor蓝图&#xff0c;然后在该蓝图中添加一个“Cascade Particle System Component” 2. 在右侧的细节面板中&#xff0c;点击“模板”一项中的下拉框&#xff0c;然后点击“Cascade粒子系统&#xff08;旧版&#xff09;” 然后就可以选择在哪个路径下创建级…

Notepad++下载、使用

下载 https://notepad-plus-plus.org/downloads/ 安装 双击安装 选择安装路径 使用 在文件夹中搜索 文件类型可以根据需要设置 如 *.* 说明是所有文件类型&#xff1b; *.tar 说明是所有文件后缀是是tar的文件‘&#xff1b;

【Rust日报】2023-10-30 理解 Rust 中的生命周期

理解 Rust 中的生命周期 生命周期&#xff08;Lifetime&#xff09;是让 Rust 成为 Rust 的关键因素。 没有了生命周期&#xff0c;轻松的并发、直接的内存分配和整体的数据安全都是不可能的。 但是&#xff0c;生命周期也很难理解&#xff0c;这篇教程会帮助人们理解生命周期的…

【强化学习】13 —— Actor-Critic 算法

文章目录 REINFORCE 存在的问题Actor-CriticA2C&#xff1a; Advantageous Actor-Critic代码实践结果 参考 REINFORCE 存在的问题 基于片段式数据的任务 通常情况下&#xff0c;任务需要有终止状态&#xff0c;REINFORCE才能直接计算累计折扣奖励 低数据利用效率 实际中&#…

【Java】多线程案例(单例模式,阻塞队列,定时器,线程池)

❤️ Author&#xff1a; 老九 ☕️ 个人博客&#xff1a;老九的CSDN博客 &#x1f64f; 个人名言&#xff1a;不可控之事 乐观面对 &#x1f60d; 系列专栏&#xff1a; 文章目录 实现安全版本的单例模式饿汉模式类和对象的概念类对象类的静态成员与实例成员 懒汉模式如何保证…