【贪心算法】leetcode刷题

news2024/9/24 1:18:42

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

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 = 0
        si = 0
        for gi in g:
            if si<len(s) and s[si]>=gi:   # 饼干要大于胃的容量,才能喂饱
                count+=1
                si+=1             
        return count

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

class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        g = sorted(g)
        s = sorted(s)
        count = 0
        gi = 0
        for si in s:
            if gi<len(g) and g[gi]<=si:  # 胃的容量要小于等于饼干大小才能喂饱
                count+=1
                gi+=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 1
            return len(nums)
        # 情况一以及情况三:
        prediff = 0
        for 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+=1
                prediff = curdiff   # 更新prediff
        return 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 = 0
        for i in dp:
            if i>0:
                res+=i
        return 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 = 0
        if n<2:
            return True
        for i in range(n-1):
            if cover>=i:
                cover = max(cover,i+nums[i])
            if cover>=n-1:
                return True
        return 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 += 1
        
        return 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-=1
                nums[i] = -nums[i]
                
        # 现在全部都是正数了
        if k%2==1: # 如果还剩奇数个,则将最小的正数翻转
            nums[-1] = -nums[-1]

        # 如果是偶数,其实不用管,因为随便翻转个正数偶数次就可以了,不影响最后结果
        return sum(nums)

134. 加油站

分发糖果

在这里插入图片描述

  • 从左到右:
    如果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)

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

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

相关文章

Win11大小写切换图标关闭方法

大家使用Win11操作系统的时候经常会切换大小写键盘&#xff0c;有些游戏本在游戏过程中需要切换大小写&#xff0c;这个时候电脑的屏幕就会出现大小写切换的图标而影响游戏体验&#xff1b; 那么想要关闭Win11电脑上大小写切换图标&#xff0c;又不知道具体怎么操作&#xff0c…

VS Code search tab

Vs Code search 栏的应用 我发现&#xff0c;在vs code种&#xff0c;上面的搜索框的功能非常多。在最初使用vscode时候&#xff0c;以为这只是一个普通的搜索框。后来&#xff0c;发现它可以用于全局搜索文件&#xff0c;比如使用ctrlshiftp。 后来&#xff0c;我发现&#xf…

lifecycleScope Unresolved reference

描述 导入了lifecycle.lifecycleScope&#xff0c;但是在activity中使用lifecycleScope报错出现Unresolved reference找不到引用。 导包 import androidx.lifecycle.lifecycleScope使用 lifecycleScope.launch(Dispatchers.IO) {...}错误 方案 代码中的activity继承Activ…

SSM(Vue3+ElementPlus+Axios+SSM前后端分离)--功能实现【四】

文章目录 SSM--功能实现实现功能06-修改家居信息需求分析/图解思路分析代码实现注意事项和细节 实现功能07-删除家居信息需求分析/图解思路分析代码实现 实现功能08-分页显示列表需求分析/图解思路分析代码实现完成测试分页显示效果 SSM–功能实现 实现功能06-修改家居信息 需…

39.利用matlab寻找素数(matlab程序)

1.简述 MATLAB嵌套循环允许使用一个循环在另一循环内&#xff0c;下面用一个嵌套循环来把所有从1到100的素数显示出来。 2.代码 %% 学习目标&#xff1a;寻找素数 clear sum5; %求0&#xff5e;100素数之和 ss0; %用来标定是否是素数&#xff0c;0表示不是 p…

MongoDB SQL

Microsoft Windows [版本 6.1.7601] 版权所有 (c) 2009 Microsoft Corporation。保留所有权利。C:\Users\Administrator>cd C:\MongoDB\Server\3.4\binC:\MongoDB\Server\3.4\bin> C:\MongoDB\Server\3.4\bin> C:\MongoDB\Server\3.4\bin>net start MongoDB 请求的…

Mac电脑怎么使用“磁盘工具”修复磁盘

我们可以使用“磁盘工具”的“急救”功能来查找和修复磁盘错误。 “磁盘工具”可以查找和修复与 Mac 磁盘的格式及目录结构有关的错误。使用 Mac 时&#xff0c;错误可能会导致意外行为&#xff0c;而重大错误甚至可能会导致 Mac 彻底无法启动。 继续之前&#xff0c;请确保您…

【C# 基础精讲】C# 开发环境搭建(Visual Studio等)

安装C#开发环境是开始学习和使用C#编程的第一步。目前&#xff0c;最常用的C#开发环境是Microsoft Visual Studio&#xff0c;它是一套强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;提供了丰富的工具和功能&#xff0c;使开发C#应用程序变得更加便捷。以下是安装…

OSLog与NSLog对比

NSLog: NSLog的文档&#xff0c;第一句话就说&#xff1a;Logs an error message to the Apple System Log facility.&#xff0c;所以首先&#xff0c;NSLog就不是设计作为普通的debug log的&#xff0c;而是error log&#xff1b;其次&#xff0c;NSLog也并非是printf的简单…

Redis 6.5 服务端开启多线程源码

redis支持开启多线程&#xff0c;只有从socket到读取缓冲区和从输出缓冲区到socket这两段过程是多线程&#xff0c;而命令的执行还是单线程&#xff0c;并且是由主线程执行 借鉴&#xff1a;【Redis】事件驱动框架源码分析&#xff08;多线程&#xff09; 一、main启动时初始化…

nacos本地搭建+springCloud服务注册中心-nacos(简易实现)

一.nacos概述 nacos官网 二.Windows使用搭建nacos 较为完整使用参考 1.安装nacos 去nacos github下载nacos最新稳定版本&#xff0c;我用的是nacos-server-2.2.3.zip&#xff0c;下载后解压&#xff0c;得到 2.创建数据库 启动mysql&#xff0c;创建数据库nacos&#xff…

Day 72 固定激活函数的BP神经网络 (1. 网络结构理解)

代码&#xff1a; package dl;/*** Back-propagation neural networks. The code comes from*/public class SimpleAnn extends GeneralAnn{/*** The value of each node that changes during the forward process. The first* dimension stands for the layer, and the secon…

[迁移学习]领域泛化

一、概念 相较于领域适应&#xff0c;领域泛化(Domain generalization)最显著的区别在于训练过程中不能访问测试集。 领域泛化的损失函数一般可以描述为以下形式&#xff1a; 该式分为三项&#xff1a;第一项表示各训练集权重的线性组合&#xff0c;其中π为使该项最小的系数&a…

微信云托管(本地调试)⑥:nginx、vue刷新404问题

一、nginx默认路径 1.1、默认配置文件路径&#xff1a;/etc/nginx/nginx.conf 1.2、默认资源路径&#xff1a;/usr/share/nginx/html/index.html 二、修改nginx.conf配置 &#xff08;注意配置中的&#xff1a;include /etc/nginx/conf.d/*.conf; 里面包了一个server配置文件…

Typescript+React入门

初识Typescript 出现背景 Typescript&#xff08;以下简称TS&#xff09;实际上就是JavaScriptType&#xff0c;用数据类型的方式来约束了JS的变量定义 在JS的基础上增加了类型支持 在JS中大多数错误都是因为数据类型造成的&#xff0c;所以TS为了规避这个问题加入了类型限制…

Android性能优化—数据结构优化

优化数据结构是提高Android应用性能的重要一环。在Android开发中&#xff0c;ArrayList、LinkedList和HashMap等常用的数据结构的正确使用对APP性能的提升有着重大的影响。 一、ArrayList ArrayList内部使用的是数组&#xff0c;默认大小10&#xff0c;当数组长度不足时&…

探索OLED透明屏的参数及其在不同领域的应用

OLED透明屏作为一种创新的显示技术&#xff0c;具有高透明度、色彩鲜艳、观感独特等特点&#xff0c;正逐渐成为各个领域的热门选择。 为帮助您更好地了解和选择适合自己需求的OLED透明屏&#xff0c;尼伽便给您详细介绍一下OLED透明屏的参数&#xff0c;包括屏幕尺寸、分辨率…

SQL注入上传文件获取shell

SQL注入写文件的三个必要条件 Web目录有读写权限&#xff1a; 当目标网站的Web目录具有读写权限时&#xff0c;攻击者可以通过注入恶意SQL语句将恶意文件写入服务器上的Web目录。 知道文件的绝对路径&#xff1a; 攻击者需要知道目标系统上的文件的绝对路径&#xff0c;以便将…

Uni-Dock:GPU 分子对接使用教程

github文件下载&#xff1a; git clone https://github.com/dptech-corp/Uni-Dock.git cd Uni-Dock/example/screening_test wget https://github.com/dptech-corp/Uni-Dock/releases/download/1.0.0/unidock 将此文件加入到全局变量中 chmod x unidock sudo mv unidock /…

杂记 | 记录一次使用Docker安装gitlab-ce的过程(含配置交换内存)

文章目录 01 准备工作02 &#xff08;可选&#xff09;配置交换内存03 编辑docker-compose.yml04 启动并修改配置05 nginx反向代理06 &#xff08;可选&#xff09;修改配置文件07 访问并登录 01 准备工作 最近想自建一个gitlab服务来保存自己的项目&#xff0c;于是找到gitla…