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

贪心算法练习题(2024/6/18)

什么是贪心

贪心的本质是选择每一阶段的局部最优,从而达到全局最优

贪心算法一般分为如下四步:

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

1分发饼干

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

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

示例 1:

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

示例 2:

输入: g = [1,2], s = [1,2,3]
输出: 2
解释: 
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出2.

提示:

  • 1 <= g.length <= 3 * 104
  • 0 <= s.length <= 3 * 104
  • 1 <= g[i], s[j] <= 231 - 1

思路:

  1. 排序: 首先,将孩子的胃口数组 g 和饼干的大小数组 s 分别按从小到大排序。这样做是为了能够从最小的胃口和最小的饼干开始匹配,以尽可能满足更多的孩子。

  2. 贪心策略: 使用贪心算法的核心思想,从胃口最大的孩子开始,尝试给他们分配能满足他们胃口的最小饼干。这里的贪心选择是每次都选择当前能够满足的最小饼干,以期望最终能够满足尽可能多的孩子。

  3. 实现细节:

    • 使用 index 表示当前可用的饼干数组的最后一个元素的下标。
    • 从最大胃口的孩子开始向最小胃口的孩子遍历,尝试找到合适的饼干分配。
    • 如果当前的饼干能够满足当前孩子的胃口,则结果 result 加一,并将 index 减一,表示使用了这个饼干。
    • 如果当前的饼干不能满足当前孩子的胃口,则继续向前尝试下一个更大的饼干,直到找到合适的或者饼干用完。
  4. 返回结果: 最终返回 result,即能够满足的孩子的数量。

代码:

class Solution {
public:int findContentChildren(vector<int>& g, vector<int>& s) {// 将孩子数组和饼干数组按照从小到大排序sort(g.begin(), g.end()); // 按照孩子的胃口排序sort(s.begin(), s.end()); // 按照饼干的大小排序int index = s.size() - 1; // 饼干数组的下标int result = 0; // 结果,能满足孩子的数量// 从胃口最大的孩子开始匹配饼干for (int i = g.size() - 1; i >= 0; i--) { // 遍历胃口// 如果还有饼干可用且当前饼干满足当前孩子的胃口if (index >= 0 && s[index] >= g[i]) { // 遍历饼干result++; // 满足一个孩子index--; // 使用了一个饼干,下标减一}}return result; // 返回满足孩子的数量}
};

2摆动序列

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

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

  • 相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

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

示例 1:

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

示例 2:

输入:nums = [1,17,5,10,13,15,10,5,16,8]
输出:7
解释:这个序列包含几个长度为 7 摆动序列。
其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。

示例 3:

输入:nums = [1,2,3,4,5,6,7,8,9]
输出:2

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 1000

思路:

代码:

局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值

整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列只需要统计数组的峰值数量就可以了。

  1. 初始化:

    • curDiff 初始化为 0,表示当前一对相邻元素的差值。
    • preDiff 也初始化为 0,表示前一对相邻元素的差值。
    • result 初始化为 1,因为序列默认至少有一个峰值。
  2. 处理边界情况:

    • 如果数组 nums 的大小 <= 1,直接返回 nums.size(),因为这种情况下不可能形成长度大于1的摆动序列。
  3. 遍历数组:

    • 循环遍历数组 nums,从第一个元素到倒数第二个元素 (i < nums.size() - 1)。
  4. 计算差值:

    • 计算 curDiff 为 nums[i + 1] - nums[i],即当前两个相邻元素的差值。
  5. 检测峰值和谷值:

    • 当 preDiff <= 0 && curDiff > 0 或者 preDiff >= 0 && curDiff < 0 时,表示出现了摆动的峰值或者谷值。
    • 在这些情况下,增加 result 的计数,因为它们是摆动序列的关键点。
  6. 返回结果:

    • 最终返回 result,即最长摆动子序列的长度。

class Solution {
public:int wiggleMaxLength(vector<int>& nums) {if (nums.size() <= 1) return nums.size();int curDiff = 0; // 当前一对差值int preDiff = 0; // 前一对差值int result = 1;  // 记录峰值个数,序列默认序列最右边有一个峰值for (int i = 0; i < nums.size() - 1; i++) {curDiff = nums[i + 1] - nums[i];// 出现峰值if ((preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)) {result++;preDiff = curDiff; // 注意这里,只在摆动变化的时候更新prediff}}return result;}
};

3最大子数组和

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

子数组

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

示例 1:

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

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

思路:

局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。

全局最优:选取最大“连续和”

局部最优的情况下,并记录最大的“连续和”,可以推出全局最优

该贪心算法实现的思路是在遍历数组的过程中,持续累积子数组的元素和,同时不断更新最大子数组之和。如果当前累积和变为负数,就重新开始计算子数组和,以期获得更大的子数组和。

代码:

class Solution {
public:int maxSubArray(vector<int>& nums) {int result = INT32_MIN; // 初始化最大和为负无穷int count = 0; // 当前累积和for (int i = 0; i < nums.size(); i++) {count += nums[i]; // 累加当前元素到当前和if (count > result) {result = count; // 更新最大和为当前和}if (count <= 0) {count = 0; // 如果当前和小于等于0,则重新开始计算累积和}}return result; // 返回最大和}
};

http://www.lryc.cn/news/380850.html

相关文章:

  • 4.1 四个子空间的正交性
  • RabbitMQ实践——使用WebFlux响应式方式实时返回队列中消息
  • SpringBoot前后端传递数据时常用的JSON格式数据是什么?【讲解JSON概念、语法、以及Java对象互转】
  • mysql学习——SQL中的DQL和DCL
  • windows系统上nginx搭建文件共享
  • 星闪指向遥控,做家电交互的破壁人
  • SpringBoot使用AutoConfigure实现依赖库自动导入配置
  • QT中利用动画弄一个侧边栏窗口,以及贴条效果
  • win10免安装配置MySQL8.4.0
  • VS Code安装及环境配置(超详细)
  • shell脚本通过解析日志使用串口开关屏知识点整理
  • 速盾:视频cdn和网站cdn的相同点与不同点
  • 37.自定义协议
  • 【React Native】measureInWindow在安卓上无法正确获取View在屏幕上的布局信息
  • C++ 教程 - 04 类的使用
  • excel按模板文件导出多个文件并压缩为ZIP格式返回前端
  • 自动驾驶仿真测试用例表格示例 ACC ELK FCW
  • 数组 (java)
  • 时序预测 | Matlab基于Transformer多变量时间序列多步预测
  • suuk-s.php.jpg-python 库劫持
  • python3GUI--ktv点歌软件By:PyQt5(附下载地址)
  • opencascade AIS_InteractiveContext源码学习2
  • scale()函数详解
  • 计算机基础学习有多重要?学哪些?如何学?
  • Oracle day9
  • Race Condition竞争条件
  • docker 删除本地镜像释放磁盘空间
  • JVM中的垃圾回收器
  • 记录一些可用的AI工具网站
  • vue3页面传参