当前位置: 首页 > article >正文

贪心算法实战3

文章目录

  • 前言
  • 区间问题
    • 跳跃游戏
    • 跳跃游戏II
    • 用最少数量的箭引爆气球
    • 无重叠区间
    • 划分字母区间
    • 合并区间
  • 最大子序和
  • 加油站
  • 监控二叉树

前言

今天继续带大家进行贪心算法的实战篇3,本章注意来解答一些运用贪心算法的比较难的问题,大家好好体会,怎么从构建局部最优到全局最优的。一文带大家弄懂。本文用于记录自己的学习过程,同时向大家进行分享相关的内容。本文内容参考于代码随想录同时包含了自己的许多学习思考过程,如果有错误的地方欢迎批评指正!

image-20250516170158923

区间问题

跳跃游戏

55. 跳跃游戏 - 力扣(LeetCode)

image-20250516171038433

**相关技巧:**其实跳跃游戏的解题思路就类似于一个搭桥的过程。如下所示,每一步都有个长度,我用着这个长度来搭桥,用来更新我能够最远到达的地方,如果能够到达终点,那么我们搭建的桥就肯定能够超过最大的下标。

image-20250528165639557

这道题目关键点在于:不用拘泥于每次究竟跳几步,而是看覆盖范围,覆盖范围内一定是可以跳过来的,不用管是怎么跳的。

class Solution:def canJump(self, nums: List[int]) -> bool:cover = 0if len(nums) == 1: return Truei = 0# python不支持动态修改for循环中变量,使用while循环代替while i <= cover:cover = max(i + nums[i], cover)if cover >= len(nums) - 1: return Truei += 1return False

跳跃游戏II

45. 跳跃游戏 II - 力扣(LeetCode)

image-20250516171100828

**相关技巧:**这题确实比刚才的跳跃游戏难了点,但其实本质上是一样的,这回题目说了肯定能够到达终点的。那我们考虑的就是怎么用最少的次数跳过去。

其实很简单,我们来看,2,3,1,1,4,从第一格开始我们能跳最远两步,然后我们跳的这两步之内,能够延伸我的桥,就是能跳的最远的,怎么让步数最少就是我们在我们能跳的格子内,哪一个能够让我们的桥延伸的更远,搭的更远就是我们需要的,最终得到的结果肯定就是最少的跳跃次数了。而且也很经典的贪心思想了。

class Solution:def jump(self, nums):cur_distance = 0  # 当前覆盖的最远距离下标ans = 0  # 记录走的最大步数next_distance = 0  # 下一步覆盖的最远距离下标for i in range(len(nums) - 1):  # 注意这里是小于len(nums) - 1,这是关键所在next_distance = max(nums[i] + i, next_distance)  # 更新下一步覆盖的最远距离下标if i == cur_distance:  # 遇到当前覆盖的最远距离下标cur_distance = next_distance  # 更新当前覆盖的最远距离下标ans += 1return ans

用最少数量的箭引爆气球

452. 用最少数量的箭引爆气球 - 力扣(LeetCode)

image-20250516171127042

**相关技巧:**如何用最少的弓箭呢?那不肯定就得是每次射掉重叠最多的气球,那最后用的肯定就是最少的弓箭了。

那重点来了,我们怎么去判定重叠的情况,去确定重叠的时候射哪个位置呢?

image-20250528172307610

其实就是确定其最右边界,而且射爆气球后,我们也不需要从中删掉,只需要向下一个遍历即可。

所以理解了之后,再看这道题就很容易解出来了。看代码就能深刻的理解了。首先先进行排序,然后遍历,找最右边界的过程,当超过了就加一支箭。

class Solution:def findMinArrowShots(self, points: List[List[int]]) -> int:if len(points) == 0: return 0points.sort(key=lambda x: x[0])result = 1for i in range(1, len(points)):if points[i][0] > points[i - 1][1]: # 气球i和气球i-1不挨着,注意这里不是>=result += 1     else:points[i][1] = min(points[i - 1][1], points[i][1]) # 更新重叠气球最小右边界return result

无重叠区间

435. 无重叠区间 - 力扣(LeetCode)

image-20250516171215848

**相关技巧:**来看这道题,我们要找的无重叠区间,这么看好像是没有什么思路。但是我们想一下,我们去射气球的时候找的是什么,重叠区间,那我们将重叠区间找出来了,直接总区间减去重叠区间,剩下的就是我们需要去移除的区间了。

所以我们要做的与用最少数量的箭引爆气球是一样的,首先按照左边界升序排列,我们在找出重叠的区间,注意这里仅仅有一个细节不一样,射气球的时候 i n t e r v a l s [ i ] [ 0 ] > i n t e r v a l s [ i − 1 ] [ 1 ] intervals[i][0] > intervals[i - 1][1] intervals[i][0]>intervals[i1][1]这里是不带等号的,因为那时候题目说是算重叠的,但是本题就得带等号了,因为在这题里面这就不算重叠了。

最后我们找出所有的重叠区间,让总区间减去重叠的区间就是我们需要去移除的区间了。

class Solution:def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:if not intervals:return 0intervals.sort(key=lambda x: x[0])  # 按照左边界升序排序result = 1  # 不重叠区间数量,初始化为1,因为至少有一个不重叠的区间for i in range(1, len(intervals)):if intervals[i][0] >= intervals[i - 1][1]:  # 没有重叠result += 1else:  # 重叠情况intervals[i][1] = min(intervals[i - 1][1], intervals[i][1])  # 更新重叠区间的右边界return len(intervals) - result

划分字母区间

763. 划分字母区间 - 力扣(LeetCode)

image-20250516171235520

**相关技巧:**在遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。

可以分为如下两步:

  • 统计每一个字符最后出现的位置
  • 从头遍历字符,并更新字符的最远出现下标,如果找到字符最远出现位置下标和当前下标相等了,则找到了分割点

一张图片你就能很清晰的懂得了,然后写出代码即可

image-20250529113708492

class Solution:def partitionLabels(self, s: str) -> List[int]:last_occurrence = {}  # 存储每个字符最后出现的位置for i, ch in enumerate(s):last_occurrence[ch] = iresult = []start = 0end = 0for i, ch in enumerate(s):end = max(end, last_occurrence[ch])  # 找到当前字符出现的最远位置if i == end:  # 如果当前位置是最远位置,表示可以分割出一个区间result.append(end - start + 1)start = i + 1return result

合并区间

56. 合并区间 - 力扣(LeetCode)

image-20250516171256274

**相关技巧:**本题的本质其实还是判断重叠区间问题。其实还是一个套路,只不过区别就是判断区间重叠后的逻辑,本题是判断区间重贴后要进行区间合并。

所以一样的套路,先排序,让所有的相邻区间尽可能的重叠在一起,按左边界,或者右边界排序都可以,处理逻辑稍有不同。

按照左边界从小到大排序之后,如果 intervals[i][0] <= intervals[i - 1][1] 即intervals[i]的左边界 <= intervals[i - 1]的右边界,则一定有重叠。(本题相邻区间也算重贴,所以是<=)

class Solution:def merge(self, intervals):result = []if len(intervals) == 0:return result  # 区间集合为空直接返回intervals.sort(key=lambda x: x[0])  # 按照区间的左边界进行排序result.append(intervals[0])  # 第一个区间可以直接放入结果集中for i in range(1, len(intervals)):if result[-1][1] >= intervals[i][0]:  # 发现重叠区间# 合并区间,只需要更新结果集最后一个区间的右边界,因为根据排序,左边界已经是最小的result[-1][1] = max(result[-1][1], intervals[i][1])else:result.append(intervals[i])  # 区间不重叠return result

最大子序和

53. 最大子数组和 - 力扣(LeetCode)

image-20250516171317288

**相关技巧:**首先我们来看题目,我们需要求最大和的连续子数组,那么怎么去得到最大呢?很简单,我们需要保证当前的连续和是大于零的,这样我们加入下一个数的时候就不会拖累下一个数。这也就是贪心思想的体现。

比如说当前第一个-2,要加下一个1了,我们需要去加这个-2吗?之前的连续和都变成负数了,对于我们后面的找最大连续和来说一定会是个累赘。所以我们下一个就是1开始,然后加-3变成-2。又变成负数了,再从下一个重新开始。4加-1是3,虽然减少了,但是其还是正的,会对下一个数的累加有帮助,**当然了,我们这里会有个记录最大的,如果后面加起来成负数了,就会记录上4是最大的。**所以继续加2,变成5,再加1变成6,**这里会记录上,更新之后最大的是6的。**然后在加-5和4,变成5,虽然也是正的,但是之前记录了最大的就是6,所以我们的最大连续子数组和是6。

class Solution:def maxSubArray(self, nums):result = float('-inf')  # 初始化结果为负无穷大count = 0for i in range(len(nums)):count += nums[i]if count > result:  # 取区间累计的最大值(相当于不断确定最大子序终止位置)result = countif count <= 0:  # 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和count = 0return result

加油站

134. 加油站 - 力扣(LeetCode)

image-20250516171341261

**相关技巧:**首先来看题目,我们进行分析:如果总油量减去总消耗大于等于零那么一定可以跑完一圈,说明 各个站点的加油站 剩油量rest[i]相加一定是大于等于零的。每个加油站的剩余量rest[i]为gas[i] - cost[i]。

i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起,再从0计算curSum。

image-20250529134019678

class Solution:def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:curSum = 0  # 当前累计的剩余油量totalSum = 0  # 总剩余油量start = 0  # 起始位置for i in range(len(gas)):curSum += gas[i] - cost[i]totalSum += gas[i] - cost[i]if curSum < 0:  # 当前累计剩余油量curSum小于0start = i + 1  # 起始位置更新为i+1curSum = 0  # curSum重新从0开始累计if totalSum < 0:return -1  # 总剩余油量totalSum小于0,说明无法环绕一圈return start

监控二叉树

968. 监控二叉树 - 力扣(LeetCode)

image-20250516171401403

**相关技巧:**我们从题目中其实能看出来,摄像头是不会放在叶子节点的,因为摄像头能够覆盖上中下三层,所以放在叶子节点或者头节点就会特别浪费,其次我们遍历从叶子节点开始往上遍历,为什么不从头节点呢?因为哪怕头节点放一个摄像头就只浪费一个,但是叶子节点的话那就是指数级别的了。所以我们的遍历顺序选择后序遍历。

我们用三个数字来表示不同的状态,这样方便我们判定是否放摄像头:

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

主要有如下四类情况:

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

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

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

  • 情况4:头结点没有覆盖

所以我们需要加摄像头的情况只有情况1和情况4。

class Solution:# Greedy Algo:# 从下往上安装摄像头:跳过leaves这样安装数量最少,局部最优 -> 全局最优# 先给leaves的父节点安装,然后每隔两层节点安装一个摄像头,直到Head# 0: 该节点未覆盖# 1: 该节点有摄像头# 2: 该节点有覆盖def minCameraCover(self, root: TreeNode) -> int:# 定义递归函数result = [0]  # 用于记录摄像头的安装数量if self.traversal(root, result) == 0:result[0] += 1return result[0]def traversal(self, cur: TreeNode, result: List[int]) -> int:if not cur:return 2left = self.traversal(cur.left, result)right = self.traversal(cur.right, result)# 情况1: 左右节点都有覆盖if left == 2 and 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 or right == 0:result[0] += 1return 1# 情况3:# left == 1 && right == 2 左节点有摄像头,右节点有覆盖# left == 2 && right == 1 左节点有覆盖,右节点有摄像头# left == 1 && right == 1 左右节点都有摄像头if left == 1 or right == 1:return 2

相关文章:

贪心算法实战3

文章目录 前言区间问题跳跃游戏跳跃游戏II用最少数量的箭引爆气球无重叠区间划分字母区间合并区间 最大子序和加油站监控二叉树 前言 今天继续带大家进行贪心算法的实战篇3&#xff0c;本章注意来解答一些运用贪心算法的比较难的问题&#xff0c;大家好好体会&#xff0c;怎么…...

linux、docker、git相关操作

1 linux 1.1解压缩 1.1.1 zip zip xxx.zip file 把file压缩成xxx.zip -r 递归压缩&#xff1a; zip -r example_new.zip 示例集 # 新建压缩包并命名为 example_new.zip zip -r xxx.zip file1 file2 dir1 将多个文件目录压成zip包 unzip file.zip -d target_dir #把file.zip解…...

实测,大模型谁更懂数据可视化?

大家好&#xff0c;我是 Ai 学习的老章 看论文时&#xff0c;经常看到漂亮的图表&#xff0c;很多不知道是用什么工具绘制的&#xff0c;或者很想复刻类似图表。 实测&#xff0c;大模型 LaTeX 公式识别&#xff0c;出乎预料 前文&#xff0c;我用 Kimi、Qwen-3-235B-A22B、…...

小程序32-简易双向数据绑定

在WXML中&#xff0c;普通属性的绑定是单向的&#xff0c;例如:<input value"{{value}}" /> 如果希望用户输入数据的同时改变data中的数据&#xff0c;可以借助简易双向绑定机制。在对应属性之前添加model:前缀即可: 例如<input model:value"{{value}…...

jenkins报错java.lang.OutOfMemoryError: Java heap space

报错信息 2025-05-27 09:17:16.2340000 [id38] WARNING j.u.ErrorLoggingScheduledThreadPoolExecutor#afterExecute: failure in task not wrapped in SafeTimerTask java.lang.OutOfMemoryError: Java heap spaceat java.base/java.lang.StringUTF16.compress(StringUTF16.j…...

leetcode669.修剪二叉搜索树:递归法利用有序性精准剪枝

一、题目深度解析与BST特性应用 题目描述 给定一棵二叉搜索树&#xff08;BST&#xff09;和一个值区间[low, high]&#xff0c;修剪BST使得所有节点的值都落在该区间内。修剪后的树必须保持BST的性质&#xff0c;且不能改变原有节点的相对位置关系。 BST的核心特性应用 二…...

Spring Boot 中 @RequestParam 和 @RequestPart 的区别详解(含实际项目案例)

Spring Boot 中 RequestParam 和 RequestPart 的区别详解&#xff08;含实际项目案例&#xff09; 在日常的 Spring Boot 开发中&#xff0c;我们经常会遇到表单提交、文件上传、JSON 参数绑定等需求。而在处理这类请求时&#xff0c;两个常见的注解——RequestParam 和 Reque…...

Linux入门(十一)进程管理

Linux 中每个执行的程序都称为一个进程&#xff0c;每个进程都分配一个ID号&#xff08;PID&#xff09; 每个进程都可能以两种方式存在&#xff0c;前台&#xff08;屏幕上可以操作的&#xff09;和后台&#xff08;屏幕上无法看到的&#xff09;&#xff0c;一般系统的服务都…...

【课堂笔记】EM算法

文章目录 背景极大似然估计隐变量高斯混合模型EM算法合理性分析相关好文章背景 EM算法(期望最大化算法,Expectation-Maximization Algorithm)是一种迭代优化算法,用于在含有隐变量的概率模型中估计最大似然参数。   这是概括性的定义,下面我会解释其中的名词并用具体例子…...

怎样将win11+ubuntu双系统的ubuntu从机械硬盘迁移至固态硬盘(1)

将 Ubuntu 从机械硬盘迁移到固态硬盘是一个涉及多个步骤的过程。以下是一个基本的迁移指南&#xff1a; 1. 前期准备 1.1 备份数据&#xff1a; 确保你已备份数据&#xff0c;以防止在迁移过程中出现意外导致任何数据丢失。 1.2 固态硬盘安装&#xff1a; 确保固态硬盘正确…...

el-table设置自定义css

隔行变色、表头颜色 // 设置table字体颜色、背景色 .el-table {color: #ffffff;background-color: transparent !important; }设置隔行变色功能 .el-table__body {tr.el-table__row {&:nth-child(even) {td.el-table__cell {background-color: #08417f;}}&:nth-child(…...

Compose中导航跳转的实现NavHost

文章目录 1、添加依赖2、两个页面导航跳转的实现2.1 定义导航图2.2 创建导航控制器2.3 实现两个页面跳转 2、带参数的导航2.1 定义带参数的路径2.2 定义接收参数2.3 导航到带参数的屏幕 3、关键点 1、添加依赖 // build.gradle dependencies {implementation "androidx.n…...

VSCode/Cursor中Red Hat Dependency Analytics扩展的自动依赖注入files:分析

VSCode/Cursor中Red Hat Dependency Analytics扩展的自动依赖注入files:分析 问题描述 最近在使用VSCode开发时&#xff0c;发现一个令人困扰的问题&#xff1a;每次打开或保存package.json文件时&#xff0c;都会自动添加一个自引用的依赖项。具体表现为&#xff1a; {&quo…...

【技能篇】RabbitMQ消息中间件面试专题

1. RabbitMQ 中的 broker 是指什么&#xff1f;cluster 又是指什么&#xff1f; 2. 什么是元数据&#xff1f;元数据分为哪些类型&#xff1f;包括哪些内容&#xff1f;与 cluster 相关的元数据有哪些&#xff1f;元数据是如何保存的&#xff1f;元数据在 cluster 中是如何分布…...

Linux研学-环境搭建

一 概述 1 Linux 概述 Linux系统由内核、Shell、文件系统、应用程序及系统库等关键部分组成。内核作为核心&#xff0c;管理硬件资源与系统服务&#xff1b;Shell提供用户与系统交互的命令行界面&#xff0c;让用户能便捷执行操作&#xff1b;文件系统负责数据的存储、组织与管…...

Ubuntu系统下可执行文件在桌面单击运行教程

目录 ​编辑 操作环境&#xff1a;这个可执行文件在原目录下还有它的依赖文件 1&#xff0c;方法1&#xff1a;创建启动脚本 操作步骤​&#xff1a; &#xff08;1&#xff09;​​在桌面创建脚本文件​​&#xff08;如 run_main_improve.sh&#xff09;&#xff1a; ​…...

Linux之文件进程间通信信号

Linux之文件&进程间通信&信号 文件文件描述符文件操作重定向缓冲区一切皆文件的理解文件系统磁盘物理结构&块文件系统结构 软硬链接 进程间通信匿名管道命名管道system V共享内存 信号 文件 首先&#xff0c;Linux下一切皆文件。对于大量的文件&#xff0c;自然要…...

shell脚本打包成可以在麒麟桌面操作系统上使用的deb包

以下是将 .sh 的 shell 脚本打包成可以在麒麟桌面操作系统上使用的 .deb 包的详细步骤和分析过程&#xff1a; 准备工作 安装必要的工具&#xff1a;在麒麟桌面操作系统上&#xff0c;需要安装 dh-make 和 devscripts 等工具&#xff0c;这些工具用于生成和构建 Debian 包。打…...

代码随想录算法训练营 Day61 图论ⅩⅠ Floyd A※ 最短路径算法

图论 题目 97. 小明逛公园 本题是经典的多源最短路问题。 在这之前我们讲解过&#xff0c;dijkstra朴素版、dijkstra堆优化、Bellman算法、Bellman队列优化&#xff08;SPFA&#xff09; 都是单源最短路&#xff0c;即只能有一个起点。 而本题是多源最短路&#xff0c;即求多…...

【Python】yield from 功能解析

yield from 功能解析 1.基本功能1.1 传统写法&#xff08;手动迭代&#xff09;1.2 使用 yield from 2.与普通 yield 的区别3.yield from 的底层行为4.关键应用场景场景 1&#xff1a;拼接多个生成器&#xff08;如 gen_concatenate&#xff09;场景 2&#xff1a;捕获子生成器…...

私有云大数据部署:从开发到生产(Docker、K8s、HDFS/Flink on K8s)

✅ 背景 在数据工程进入深水区后,很多企业选择将大数据平台迁移到私有云或混合云部署:一方面降低成本,另一方面增强数据安全掌控。本文将详细介绍如何在私有云中部署高可用的大数据平台,涵盖: 大数据组件的容器化 Flink on Kubernetes 部署方案 HDFS 本地/远程存储支持 运…...

改写自己的浏览器插件工具 myChromeTools

1. 起因&#xff0c; 目的: 前面我写过&#xff0c; 自己的一个浏览器插件小工具 最近又增加一个小功能&#xff0c;可以自动滚动页面&#xff0c;尤其是对于那些瀑布流加载的网页。最新的代码都在这里 2. 先看效果 3. 过程: 代码 1, 模拟鼠标自然滚动 // 处理滚动控制逻辑…...

python-pptx去除形状默认的阴影

文章目录 效果原理1. 阴影继承机制解析2. XML层操作细节3. 注意事项 扩展应用1. 批量去除阴影2. 复合效果控制 效果 右边这个是直接添加一个形状。可以看到它会默认被赋予一个阴影。 然而&#xff0c;这个东西在特定的场合&#xff0c;其实是我们所不需要的。 那怎么把这个阴…...

kuboard自带ETCD存储满了处理方案

一、前言 当运行 ETCD 日志报 Erro: mvcc database space exceeded 时&#xff0c;说明 ETCD 存储不足了&#xff08;默认 ETCD 存储是 2G&#xff09;&#xff0c;配额会触发告警&#xff0c;然后 Etcd 系统将进入操作受限的维护模式。 通过下面命令可以查看 ETCD 存储使用情…...

SpringBoot+tabula+pdfbox解析pdf中的段落和表格数据

一、前言 在日常业务需求中&#xff0c;往往会遇到解析pdf文件中的段落或者表格数据的需求。 常见的做法是使用 pdfbox 来做&#xff0c;但是它只能提取文本数据&#xff0c;没有我们在文件页面上面的那种结构化组织&#xff0c;文本通常是散乱的包含各种换行回车空格等格式&a…...

外包项目交付后还能怎么加固?我用 Ipa Guard 给 iOS IPA 增加了一层保障

在我们技术团队的日常工作中&#xff0c;接手外包开发者提交的 iOS 项目是一件常见的事。但你有没有遇到过这种情况&#xff1a;只交付了 IPA 文件&#xff0c;没有源码&#xff0c;也不方便追溯开发过程&#xff0c;但客户要求“上线前必须加一层安全防护”。 这是我们最近真…...

GitHub push失败解决办法-fatal: unable to access ‘https://github.com/xxx

问题描述&#xff1a; 问题解决&#xff1a; 1、首先查找自己电脑的代理地址和端口 windows教程如下&#xff1a; 1、搜索控制面板-打开Internet选项 2、点击局域网设置&#xff1a; 3、如图为地址和端口号 即可获得本机地址和端口号 2、根据上一步获得的本机地址和端口号为…...

USB MSC SCCI

&#x1f50d; ​数据包完整内容​ 0000 1b 00 10 09 22 8b 8b 9b ff ff 00 00 00 00 09 00 0010 00 02 00 02 00 02 03 1f 00 00 00 55 53 42 43 10 0020 09 22 8b 00 02 00 00 80 00 0a 28 00 00 00 00 00 0030 00 00 01 00 00 00 00 00 00 00 ⚙️ ​一、…...

解决Acrobat印前检查功能提示无法为用户配置文件问题

转载&#xff1a;https://zhuanlan.zhihu.com/p/18845570057 Acrobat整理页面时往往需要用到印前检查功能中的将页面缩放为A4&#xff0c;可以一键统一PDF文件所有页面大小&#xff0c;十分快捷。 不过&#xff0c;最新版本的Acrobat在安装时尽管勾选了可选功能-印前检查往往…...

华为OD最新机试真题-反转每对括号间的子串-OD统一考试(B卷)

题目描述: 给出一个字符串s(仅含有小写英文字母和括号)。 请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。注意,您的结果中不应包含任何括号。 示例1: 输入: s = “(abcd)” 输出: “dcba” 示例2:...