算法训练营第二十三天 | 贪心算法(一)

devtools/2025/3/27 8:07:20/

文章目录

  • 一、贪心算法理论基础
  • 二、Leetcode 455.分发饼干
  • 二、Leetcode 376. 摆动序列
  • 三、Leetcode 53. 最大子序和


一、贪心算法理论基础

贪心算法是一种在每一步选择中都采取当前状态下的最优决策,从而希望最终达到全局最优解的算法设计技术。

基本思想

  • 贪心算法总是做出在当前看来是最优的选择,也就是说,它不从整体最优上加以考虑,所做出的仅仅是在某种意义上的局部最优解。它通常以自顶向下的方式进行,每一步都选择一个局部最优解,逐步构造出问题的解。

使用条件

  • 贪心选择性质:问题的整体最优解可以通过一系列局部最优的选择来达到。即每一步的最优选择最终能导致全局的最优解。
  • 最优子结构性质:问题的最优解包含了子问题的最优解。也就是说,原问题的最优解可以由子问题的最优解组合而成。

一般解题步骤

  1. 将问题分解为若干个子问题
  2. 找出适合的贪心策略
  3. 求解每一个子问题的最优解
  4. 将局部最优解堆叠成全局最优解

二、Leetcode 455.分发饼干

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是满足尽可能多的孩子,并输出这个最大数值。

示例:

python">输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 
你有三个孩子和两块小饼干,3 个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是 1,你只能让胃口值是 1 的孩子满足。
所以你应该输出 1

引用:

原文链接:https://programmercarl.com/0455.%E5%88%86%E5%8F%91%E9%A5%BC%E5%B9%B2.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
题目链接:https://leetcode.cn/problems/assign-cookies/description/
视频讲解:https://www.bilibili.com/video/BV1MM411b7cq/

为了满足更多的小孩,就不要造成饼干尺寸的浪费。

大尺寸的饼干既可以满足胃口大的孩子也可以满足胃口小的孩子,那么就应该优先满足胃口大的。

这里的局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。

要更多的节省饼干,所以每个小孩分到的饼干够用就行。

先将两个数组进行排序,然后利用双指针算法,每个孩子选择最小且够吃的饼干。

代码:

python">class Solution:def findContentChildren(self, g: List[int], s: List[int]) -> int:count = 0s.sort()g.sort()i = 0j = 0while i<len(g) and j<len(s):if s[j] >= g[i]:j += 1i += 1count += 1else:j += 1return count

二、Leetcode 376. 摆动序列

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。

相反,[1, 4, 7, 2, 5][1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。

示例:

python">输入:nums = [1,7,4,9,2,5]
输出:6
解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3)

引用:

原文链接:https://programmercarl.com/0376.%E6%91%86%E5%8A%A8%E5%BA%8F%E5%88%97.html
题目链接:https://leetcode.cn/problems/wiggle-subsequence/description/
视频讲解:https://www.bilibili.com/video/BV17M411b7NS/

源自代码随想录

我们借用一下代码随想录给出的图片,这样就很好理解我们都需要做什么事情。

图中给出要删除非摆动的点,其实只是方便我们理解。我们在实际操作中并不需要去复杂的删除点,只需要记录一下摆动点的数量即可。

我们定义两个变量 preddiff==num[i]-nums[i-1]curdiff=nums[i+1]-nums[i],用来记录某个点左右的变化值,所以我们的终止条件就可以写为如下形式

python">if (prediff>0 and curdiff<0) or (prediff<0 and curdiff>0):result += 1

在此基础上,我们还有三个需要注意的细节。

上下坡中有平路
源自代码随想录
在这里最后一个 2,我们的 prediff 值等于零, curdiff 小于零,这种情况我们也算是一种摆动,所以我们也需要记录一下。我们就需要完善一下终止条件:

python">if (prediff>=0 and curdiff<0) or (prediff<=0 and curdiff>0):result += 1

首尾值
当数组只有两个值的时候,我们这种判断条件需要三个值,会发生 IndexError

我们可以在数组开头前面默认多加一个平路(并不是真正的去添加一个元素),并设置 prediff 的初始值就为零,这样上面的判断条件完全可以涵盖这种情况。

对于最后一个元素,根据题目描述它是一定会形成一个摆动的,所以我们在循环的时候就不遍历最后一个元素,并且设置初始结果的值为 1

python">result = 1
prediff = 0
for i in range(len(nums)-1):pass

单调坡中有平路
源自代码随想录
由图中可以看出,第一个 2 和最后一个 2 都是符合我们记录摆动值的条件,最后摆动的结果是 3,但是我们实际的摆动结果是 2

我们在记录 prediff 的值的时候并不是直接使用 nums[i]-nums[i-1] 进行赋值,而是不断的去跟踪 curdiff 的值。

我们只需要在这个坡度摆动变化的时候,更新 prediff 就行,这样 prediff 在 单调区间有平坡的时候就不会发生变化,造成我们的误判。

代码:

python">class Solution:def wiggleMaxLength(self, nums: List[int]) -> int:result = 1prediff = 0curdiff = 0if len(nums) == 1:return resultfor i in range(len(nums)-1):curdiff = nums[i+1] - nums[i]if (prediff<=0 and curdiff>0) or (prediff>=0 and curdiff<0):result += 1prediff = curdiffreturn result

三、Leetcode 53. 最大子序和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

示例:

python">输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6

引用:

原文链接:https://programmercarl.com/0053.%E6%9C%80%E5%A4%A7%E5%AD%90%E5%BA%8F%E5%92%8C.html
题目链接:https://leetcode.cn/problems/maximum-subarray/description/
视频讲解:https://www.bilibili.com/video/BV1aY4y1Z7ya/

暴力美学:使用两层 for 循环,外层遍历子数组的起始位置,内层循环来控制子数组的长度,最后将最大值的结果保存即可。暴力法的时间复杂度为 O(n^2),超时。

贪心思想:这题的贪心思想在于,当我们的连续和为负数时,它对后续的和起到的是副作用(越加越小),所以我们直接抛弃这段子数组,从新的结点开始。

我们使用 result 保存最大连续和的时候,这个操作一定要在判断连续和是否小于零的前面,因为最大和也有可能是负数。

代码:

python">class Solution:def maxSubArray(self, nums):# 暴力法result = float('-inf')  # 初始化结果为负无穷大count = 0for i in range(len(nums)):  # 设置起始位置count = 0for j in range(i, len(nums)):  # 从起始位置i开始遍历寻找最大值count += nums[j]result = max(count, result)  # 更新最大值return result# 贪心算法result = float('-inf')count = 0for i in range(len(nums)):count += nums[i]result = max(count, result)if count <= 0:count = 0return result

http://www.ppmy.cn/devtools/171166.html

相关文章

Jmeter插件下载和配置

下载插件&#xff1a; https://jmeter-plugins.org/wiki/PluginsManager/ https://jmeter-plugins.org/get/ 下载文件移动到jmeter安装目录&#xff1a;\apache-jmeter-5.6.3\lib\ext\重启Jmeter后Options中查看插件 4.

基于SpringBoot的名著阅读网站

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

解锁DeepSeek潜能:Docker+Ollama打造本地大模型部署新范式

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《深度探秘&#xff1a;AI界的007》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、什么是Docker 2、什么是Ollama 二、准备工作 1、操…

centos 7 搭建FTP user-list用户列表

在 CentOS 7 上搭建基于 user_list 的 FTP 用户列表&#xff0c;你可以按以下步骤操作&#xff1a; 1. 安装 vsftpd 服务 若还未安装 vsftpd&#xff0c;可以使用以下命令进行安装&#xff1a; bash yum install -y vsftpd2. 启动并设置开机自启 vsftpd 服务 bash systemctl…

Leetcode 刷题笔记 图论part05

卡码网 107 寻找存在的路径 初识并查集 并查集功能&#xff1a; 寻找根节点&#xff0c;函数: find(int u)&#xff0c;也就是判断这个节点的祖先节点是哪个将两个节点接入到同一个集合&#xff0c;函数: join(int u, int v)&#xff0c;将两个节点连在同一个根节点上判断两…

HarmonyOS next性能优化:多维度策略与实战案例

HarmonyOS next性能优化&#xff1a;多维度策略与实战案例 在HarmonyOS next开发中&#xff0c;性能优化是提升用户体验、确保应用流畅运行的关键。本文将从多个角度探讨HarmonyOS next的性能优化策略&#xff0c;并通过示例代码展示优化前后的效果对比&#xff0c;帮助开发者…

在控制台中监控 Linux 性能的十种方法

对下面的文章内容进行了总结&#xff0c;也是自己 mark 一下&#xff0c;以后用到可以直接来这里查看 https://www.jeffgeerling.com/blog/2025/top-10-ways-monitor-linux-console 10 个 linux 系统重用来查看性能的工具&#xff08;类 top&#xff09; top&#xff1a;用于…

基于WebRTC与P2P技术,嵌入式视频通话EasyRTC实现智能硬件音视频交互,适配Linux、ARM、RTOS、LiteOS

EasyRTC不仅仅是一个连接工具&#xff0c;更是一个经过深度优化的通信桥梁。它在嵌入式设备上进行了特殊优化&#xff0c;通过轻量级SDK设计、内存和存储优化以及硬件加速支持&#xff0c;解决了传统WebRTC在嵌入式设备上的适配难题&#xff0c;显著节省了嵌入式设备的资源。 1…