【贪心算法】leetcode刷题

贪心算法无固定套路。
核心思想:先找局部最优,再扩展到全局最优。

455.分发饼干

在这里插入图片描述
两种思路:
1、从大到小。局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。先遍历的胃口,在遍历的饼干
在这里插入图片描述

class Solution:def findContentChildren(self, g: List[int], s: List[int]) -> int:g = sorted(g,reverse=True)s = sorted(s,reverse=True)count = 0si = 0for gi in g:if si<len(s) and s[si]>=gi:   # 饼干要大于胃的容量,才能喂饱count+=1si+=1             return count

2、从小到大。小饼干先喂饱小胃口。两个循环的顺序改变了,先遍历的饼干,在遍历的胃口,这是因为遍历顺序变了,我们是从小到大遍历。

class Solution:def findContentChildren(self, g: List[int], s: List[int]) -> int:g = sorted(g)s = sorted(s)count = 0gi = 0for si in s:if gi<len(g) and g[gi]<=si:  # 胃的容量要小于等于饼干大小才能喂饱count+=1gi+=1    return count

376. 摆动序列

在这里插入图片描述
具体实例:
在这里插入图片描述
局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。
**整体最优:**整个序列有最多的局部峰值,从而达到最长摆动序列。

考虑几种情况:

  • 情况一:上下坡中有平坡
  • 情况二:数组首尾两端
  • 情况三:单调坡中有平坡

情况一:上下坡中有平坡
在这里插入图片描述
它的摇摆序列长度是多少呢? 其实是长度是 3,也就是我们在删除的时候 要不删除左面的三个 2,要不就删除右边的三个 2。
在这里插入图片描述
在图中,当 i 指向第一个 2 的时候,prediff > 0 && curdiff = 0 ,当 i 指向最后一个 2 的时候 prediff = 0 && curdiff < 0。
如果我们采用,删左面三个 2 的规则,那么 当 prediff = 0 && curdiff < 0 也要记录一个峰值,因为他是把之前相同的元素都删掉留下的峰值。
所以我们记录峰值的条件应该是: (preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0),为什么这里允许 prediff == 0 ,就是为了 上面我说的这种情况。

情况二:数组首尾两端
例如序列[2,5],如果靠统计差值来计算峰值个数就需要考虑数组最左面和最右面的特殊情况。
因为我们在计算 prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i])的时候,至少需要三个数字才能计算,而数组只有两个数字。
这里我们可以写死,就是 如果只有两个元素,且元素不同,那么结果为 2。
在这里插入图片描述

情况三:单调坡度有平坡
在这里插入图片描述

class Solution:def wiggleMaxLength(self, nums: List[int]) -> int:count = 1# 情况二,小于等于2的情况,可以写死if len(nums)<2:return len(nums)if len(nums)==2:if nums[-1]-nums[0]==0:return 1return len(nums)# 情况一以及情况三:prediff = 0for i in range(0,len(nums)-1):# if i>0:#     prediff = nums[i-1]-nums[i]curdiff = nums[i]-nums[i+1]if (prediff<=0 and curdiff>0) or (prediff>=0 and curdiff<0):count+=1prediff = curdiff   # 更新prediffreturn count  

122.买卖股票的最佳时机 II

在这里插入图片描述
如果想到其实最终利润是可以分解的,那么本题就很容易了!
如何分解呢?
假如第 0 天买入,第 3 天卖出,那么利润为:prices[3] - prices[0]。
相当于==(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])==。
此时就是把利润分解为每天为单位的维度,而不是从 0 天到第 3 天整体去考虑!
那么根据 prices 可以得到每天的利润序列:(prices[i] - prices[i - 1])…(prices[1] - prices[0])。

  • 局部最优:收集每天的正利润,全局最优:求得最大利润。
    在这里插入图片描述
class Solution:def maxProfit(self, prices: List[int]) -> int:n = len(prices)dp = [0]*(n-1)for i in range(1,n):dp[i-1] = prices[i]-prices[i-1]res = 0for i in dp:if i>0:res+=ireturn res

55. 跳跃游戏

在这里插入图片描述
在这里插入图片描述
每次移动取最大跳跃步数(得到最大的覆盖范围),每移动一个单位,就更新最大覆盖范围。
贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点。
i 每次移动只能在 cover 的范围内移动,每移动一个元素,cover 得到该元素数值(新的覆盖范围)的补充,让 i 继续移动下去。
而 cover 每次只取 max(该元素数值补充后的范围, cover 本身范围)。
如果 cover 大于等于了终点下标,直接 return true 就可以了

class Solution:def canJump(self, nums: List[int]) -> bool:n = len(nums)cover = 0if n<2:return Truefor i in range(n-1):if cover>=i:cover = max(cover,i+nums[i])if cover>=n-1:return Truereturn False

45.跳跃游戏 II

在这里插入图片描述
如果移动下标等于当前覆盖最大距离下标, 需要再走一步(即 ans++),因为最后一步一定是可以到的终点。(题目假设总是可以到达数组的最后一个位置),如图:
在这里插入图片描述
如果移动下标不等于当前覆盖最大距离下标,说明当前覆盖最远距离就可以直接达到终点了,不需要再走一步。如图:
在这里插入图片描述

class Solution:def jump(self, nums: List[int]) -> int: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

1005.K次取反后最大化的数组和

在这里插入图片描述

class Solution:def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:nums.sort(key=lambda x:abs(x),reverse=True)  # 按照绝对值的个数排序,且从大到小,为了后面先将前k个大负数进行翻转为正数,保证和最大for i in range(len(nums)):if nums[i]<0 and k>0:   # 将负数都翻转为正数k-=1nums[i] = -nums[i]# 现在全部都是正数了if k%2==1: # 如果还剩奇数个,则将最小的正数翻转nums[-1] = -nums[-1]# 如果是偶数,其实不用管,因为随便翻转个正数偶数次就可以了,不影响最后结果return sum(nums)

134. 加油站

135.分发糖果

在这里插入图片描述

  • 从左到右:
    如果ratings[i] > ratings[i - 1] 那么[i]的糖 一定要比[i - 1]的糖多一个,所以贪心:candyVec[i] = candyVec[i - 1] + 1
    在这里插入图片描述
  • 从右到左考虑:
    再确定左孩子大于右孩子的情况(从后向前遍历)
    遍历顺序这里有同学可能会有疑问,为什么不能从前向后遍历呢?
    因为 rating[5]与rating[4]的比较 要利用上 rating[5]与rating[6]的比较结果,所以 要从后向前遍历。
    如果从前向后遍历,rating[5]与rating[4]的比较 就不能用上 rating[5]与rating[6]的比较结果了 。如图:
    在这里插入图片描述在这里插入图片描述

如果 ratings[i] > ratings[i + 1],此时candyVec[i](第i个小孩的糖果数量)就有两个选择了,一个是candyVec[i + 1] + 1(从右边这个加1得到的糖果数量),一个是candyVec[i](之前比较右孩子大于左孩子得到的糖果数量)。
那么又要贪心了,局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。

所以就取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,candyVec[i]只有取最大的才能既保持对左边candyVec[i - 1]的糖果多,也比右边candyVec[i + 1]的糖果多。

class Solution:def candy(self, ratings: List[int]) -> int:k = len(ratings)dp = [1]*k# 从左到右for i in range(k):if i>0 and ratings[i]>ratings[i-1]:dp[i] = dp[i-1]+1# 从右到左for i in range(k-2,-1,-1):if ratings[i]>ratings[i+1]:dp[i] = max(dp[i+1]+1,dp[i])  # 关键点 见解析return sum(dp)

860. 柠檬水找零

在这里插入图片描述

class Solution:def lemonadeChange(self, bills: List[int]) -> bool:if bills[0] != 5:return Falsen = len(bills)counter = {5: 0}for i in range(n):remain = bills[i]# 添加if remain in counter.keys():counter[remain] += 1else:counter[remain] = 1# 删除 # 若有20的,先找10元的。if remain // 10 > 1 and 10 in counter.keys():if counter[10] >= (remain // 10) - 1:  # 先找10元的。counter[10] = counter[10] - ((remain // 10) - 1)remain = ((remain // 10) - 1) * 10# 删除 若是10/20,则进行删除操作if remain // 5 > 1:if counter[5] >= (remain // 5) - 1:  # 再找5元的。剩余的5个数,大于需要找回的。counter[5] = counter[5] - ((remain // 5) - 1)else:return Falsereturn True

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Kubernetes环境的高扩展机器学习部署利器——KServe

随着ChatGPT的发布&#xff0c;人们越来越难以回避利用机器学习的相关技术。从消息应用程序上的文本预测到智能门铃上的面部识别&#xff0c;机器学习&#xff08;ML&#xff09;几乎可以在我们今天使用的每一项技术中找到。 如何将机器学习技术交付给消费者是企业在开发过程中…

qt源码---事件系统之QCoreApplication

上一节分析了qt和windows系统之间的消息的传递&#xff0c;本节着重看一下&#xff0c;qt内部的事件是如何传递的&#xff1f; 1.sendEvent函数 在使用的自定义事件时&#xff0c;有时需要手动抛出一个事件&#xff0c;常用的方式有2种&#xff0c;其一时阻塞式的sendEvent函…

断路器分合闸线圈电流试验

试验目的 仅通过断路器低电压值来分析判断断路器的状态, 不能有效地反映断路器内部潜 在缺陷, 同时无法对故障进行定位, 分、 合闸线圈电流蕴含断路器操作回路的极大信 息, 典型的分、 合闸线圈动作电流暂态波形, 通常有两个波峰和一个波谷, 根据波峰、 波谷出现的时间位置, …

1 swagger简单案例

1.1 加入依赖 <!--swagger图形化接口--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version> </dependency><dependency><groupId>io.spri…

DSP学习笔记

一个汇编语句包含4个固定顺序的区域&#xff1a;标号&#xff08;必须从第一列开始 不能空格&#xff0c;后面可以有&#xff1a;也可以没有&#xff09; 助记符 操作数 注释&#xff08;用分号或者星号来注释&#xff09;伪指令用.开头&#xff0c;注释可以用第一列开始写&…

【从零开始学习JAVA | 第四十一篇】深入JAVA锁机制

目录 前言&#xff1a; 引入&#xff1a; 锁机制&#xff1a; CAS算法&#xff1a; 乐观锁与悲观锁&#xff1a; 总结&#xff1a; 前言&#xff1a; 在多线程编程中&#xff0c;线程之间的协作和资源共享是一个重要的话题。当多个线程同时操作共享数…

基于Windows手动编译openssl和直接安装openssl

零、环境 win10-64位 VS2019 一、手动编译 前言&#xff1a;对于一般的开发人员而言&#xff0c;在 openssl 上下载已经编译好的 openssl 库&#xff0c;然后直接拿去用即可&#xff0c;&#xff0c;不用手动编译&#xff0c;{见下文直接安装}。。。对于一些开发人员&#…

[webpack] 处理样式 (二)

文章目录 1.介绍2.处理 Css 资源2.1 导入包2.2 功能配置2.3 添加 Css 资源 3.处理 Less 资源3.1 导入包3.2 功能配置3.3 添加 Less 资源 4.处理 Sass 和 Scss 资源4.1 导入包4.2 配置4.3 添加 Sass 资源4.4 运行webpack 5.处理 Styl 资源5.1 导入包5.2 配置5.3 添加 Styl 资源5…

Qt--动态链接库的创建和使用

写在前面 在Qt的实际开发中&#xff0c;免不了使用和创建动态链接库&#xff0c;因此熟悉Qt中动态链接库的创建和使用对后续的库开发或使用是非常用必要的。 在之前的文章https://blog.csdn.net/SNAKEpc12138/article/details/126189926?spm1001.2014.3001.5501中已经对导入…

机器学习笔记之优化算法(八)简单认识Wolfe Condition的收敛性证明

机器学习笔记之优化算法——简单认识Wolfe Condition收敛性证明 引言回顾&#xff1a; Wolfe \text{Wolfe} Wolfe准则准备工作推导条件介绍推导结论介绍 关于 Wolfe \text{Wolfe} Wolfe准则收敛性证明的推导过程 引言 上一节介绍了非精确搜索方法—— Wolfe \text{Wolfe} Wolf…

快速修复应用程序中的问题的利器—— Android热修复

热修复技术在Android开发中扮演着重要的角色&#xff0c;它可以帮助开发者在不需要重新发布应用程序的情况下修复已经上线的应用程序中的bug或者添加新的功能。 一、热修复是什么&#xff1f; 热修复&#xff08;HotFix&#xff09;是一种在运行时修复应用程序中的问题的技术…

前端js--旋转幻灯片

效果图 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><link rel"stylesheet" href"…