[Python-贪心算法]

135. 分发糖果

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

  • 每个孩子至少分配到 1 个糖果。

  • 相邻两个孩子评分更高的孩子会获得更多的糖果。

请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目

解题思路

题目的要求是相邻两个孩子中评分更高的孩子会获得更多的糖果,这也就是说我们需要双边比较,有点像前面的求峰值点数。但是这道题让我们统计的是糖果数,双边比较的话太容易出错了。我们可以用两次单边比较求出。

第一次遍历,从左向右,这时候判断右边孩子是否大于左边孩子,如果大于,则在左边孩子获得糖果数量的基础上加1;如果不大于,则赋值为1即可。这里的初始化为赋值列表全为1即可。

第二次遍历,从右向左,这时候就要判断左孩子是否大于右孩子,如果大于,则在第一次遍历右孩子糖果数量的基础上加1,并与第一次遍历得到的左孩子糖果数量比较,取较大的那一个,因为较大的数量能同时满足两次遍历的结果;如果不大于,不作修改即可。

代码如下:

class Solution:
    def candy(self, ratings: List[int]) -> int:
        candy_ = [1] * len(ratings)
        for i in range(1,len(ratings)):
            #从左向右遍历
            if ratings[i] > ratings[i - 1]:
                candy_[i] = candy_[i - 1] + 1
            else :
                candy_[i] = 1
        print(candy_)
        for i in range(2,len(ratings) + 1):
            #从右向左遍历
            if ratings[len(ratings) - i] > ratings[len(ratings) - i + 1]:
                candy_[len(ratings) - i] = max(candy_[len(ratings) - i],candy_[len(ratings) - i + 1] + 1)
        print(candy_)
        return sum(candy_)

860. 柠檬水找零

在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。

每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。

注意,一开始你手头没有任何零钱。

给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false

解题思路

注意,这道题不能按照自己有多少钱来算,因为这样算的话会把10美元拆开,这样就会出错。正确的算法应该是对手里的5美元和10美元分别计数,按照其数目多少判断是否能够找零。

分情况讨论。

1.如果客户给了5美元,那么5美元的数值加1.

2.如果客户给了10美元,那么5美元的数值减1,10美元的数值加1。

3.如果客户给了20美元,那么优先花出10美元,再花出5美元。

因此,这里的贪心就是花出去尽可能多的10美元,保留5美元,因为5美元在找零中是万能的。

在以上三种情况中还存在着不同的情境,在第二种情况下,如果5美元的数量不够,那么返回False;在第三种情况下,如果10美元或5美元的数量不够,那么返回False。代码如下:

class Solution:
    def lemonadeChange(self, bills: List[int]) -> bool:
        five = 0
        ten = 0
        for i in range(len(bills)):
            if bills[i] == 5:
                five += 1
            elif bills[i] == 10:
                ten += 1
                if five >= 1:
                    five -= 1
                else:
                    return False
            elif bills[i] == 20:
                if ten >= 1 and five >= 1:
                    ten -= 1
                    five -= 1
                elif ten >= 1 and five <= 0:
                    return False
                elif ten <= 0 and five >= 3:
                    five -= 3
                elif ten <=0 and five < 3:
                    return False
        return True

406. 根据身高重建队列

假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好ki 个身高大于或等于 hi 的人。

请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

解题思路

这道题有点像前面的糖果题,都是从二维的角度来出题的,遇到这种类型的题,我们直接单边考虑即可。

首先我们先试试按照次序k排个序,对于[[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]],得到[[5, 0], [7, 0], [6, 1], [7, 1], [5, 2], [4, 4]],这样看数组还是很乱,身高和次序都没有排好。

我们再来尝试下按身高排序,得到[[7, 0], [7, 1], [6, 1], [5, 0], [5, 2], [4, 4]],这样的话就比较清楚些了,最起码排好了大体的身高次序,接下来只需要按照次序k插入元素即可。代码如下:

class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        people.sort(key = lambda x: (-x[0], x[1])) #按照身高从大到小,序号从小到大排
        que = []
        for p in people:
            que.insert(p[1],p)
        return que

注意,这里insert()函数的用法是,第一项p[1]代表插入的位置,这里的p[1]即为people数组中的次序k,例如[5,0]元素,就是插入到了数组中的位置0.第二项p代表需要插入的元素。

452. 用最少数量的箭引爆气球

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstartxend之间的气球。你不知道气球的确切 y 坐标。

一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 x``startx``end, 且满足 xstart ≤ x ≤ x``end,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。

给你一个数组 points返回引爆所有气球所必须射出的 最小 弓箭数

解题思路

首先来画个图直观的看一下。这里的排序是为了能让最有可能重叠的球都尽量挨在一起,便于判断。

可以发现,当球的右边界大于等于下一个球的左边界时,这两个球可以被一支箭射爆,当球的右边界小于下一个球的左边界时,这个球只能单独被射爆。

再来看可以重叠射爆的情况,两个球可以重叠时,我们怎么判断下个球能不能被重叠进去呢?观察一下就可以知道,重叠的区域是有限的,我们需要更新重叠的右边界,如上图绿线。更新之后,将新边界作为上一个球的右边界,与现在的球的左边界比较即可判断。代码如下:

class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        points.sort(key = lambda x: (x[0], x[1]))
        result = 0
        for i in range(1, len(points)):
            if points[i - 1][1] < points[i][0]:
                result += 1
            else :
                points[i][1] = min(points[i - 1][1], points[i][1])
        result += 1 #此处加一是因为循环中没法对最后一个球进行处理
        return result

435. 无重叠区间

给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠

解题思路

这道题和上道题差不多,可以按照上道题的思路进行重叠的计数,直接输出即可。代码如下:

class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        result = 0 #用于标记重叠的个数
        intervals.sort(key = lambda x:(x[0], x[1]))
        for i in range(1, len(intervals)):
            if intervals[i][0] >= intervals[i - 1][1]: #左边界大于右边界不重叠
                continue
            else: #重叠
                result += 1
                intervals[i][1] = min(intervals[i - 1][1],intervals[i][1])
        return result
​

763. 划分字母区间

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s

返回一个表示每个字符串片段的长度的列表。

解题思路

贪心算法的题一般看第一眼都没啥思路,所以这时候画个图,把所有必要信息列在图中可能就有思路了,如下:

这样思路就清晰多了,对于每个字符,我们统计出他的最远位置,然后与下标进行比较,如果下标与一段的最远位置相同了,就说明这是一段。代码如下:

class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        dic = {} #哈希表统计每个字符出现的最远位置
        for i in range(len(s)):
            dic[s[i]] = i
​
        ans = [] #存储答案
        index_max = 0 #用于表示每一段的最大下标
        len_max = 0 #用于表示每一段的最大长度
        for i in range(len(s)):
            index_max = max(dic.get(s[i], 0), index_max)
            len_max += 1
            if i == index_max:
                ans.append(len_max)
                len_max = 0
        return ans

56. 合并区间

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间

解题思路

同样画图来看。

根据图来模拟一下过程,与前面判断重叠的方法类似,都是看下一个区间的左边界与上个区间的右边界的关系来判断,只不过这里如果判为了重叠区间,则不是在对区间的右边界取最小值了,而是取最大值,因为这并不需要多个区间都有相同的一段。只需要连接在一起即可。

因为end随重叠区间改变,所以在判断为不是重叠区间时才将不重叠区间加入到答案数组中。代码如下:

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        intervals.sort(key = lambda x:(x[0], x[1]))
        ans = []
        start = intervals[0][0] #区间数组左边界
        end = intervals[0][1] #区间数组右边界
        for i in range(1, len(intervals)):
            #重叠
            if intervals[i - 1][1] >= intervals[i][0]:
                end = max(intervals[i][1], intervals[i - 1][1])
                intervals[i][1] = max(intervals[i][1], intervals[i - 1][1])
            #不重叠
            else:
                ans.append([start, end])
                start = intervals[i][0] #不重叠,更新区间数组
                end = intervals[i][1]
        ans.append([start, end])
        return ans

738. 单调递增的数字

当且仅当每个相邻位数上的数字 xy 满足 x <= y 时,我们称这个整数是单调递增的。

给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增

解题思路

这个思路比较好想,但是代码有点难写。具体思路就是将数字从尾到头遍历,如果靠后的数字小于靠前的数字,那么靠后的数字就要变为9,靠前的数字就要减一,这样才满足单调递增的要求。代码如下:

class Solution:
    def monotoneIncreasingDigits(self, n: int) -> int:
        n_s = str(n)
        index = len(n_s) #用于标记需要换为9的位置
        #不是单调递增
        for i in range(1, len(n_s)):
            if n_s[len(n_s) - i] < n_s[len(n_s) - i - 1]:
                index = len(n_s) - i
                n_s = n_s[:len(n_s) - i - 1] + str(int(n_s[len(n_s) - i - 1]) - 1) + n_s[len(n_s) - i:]
        for i in range(index, len(n_s)):
            n_s = n_s[:i] + '9' + n_s[i + 1:] 
        ans = int(n_s)
        return ans

关于字符串的操作还是不太熟练,还要继续练习。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis 面试题 | 18.精选Redis高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

数学知识第四期 快速幂

前言 快速幂在算法比赛中十分的重要&#xff0c;而且代码简短&#xff0c;清楚易懂&#xff0c;大家应该熟练掌握&#xff01;&#xff01;&#xff01; 一、什么是快速幂&#xff1f; 快速幂是一种高效的算法&#xff0c;用于计算某个数的n次幂。它的基本思想是将原式转换为…

JavaScript DOM属性和方法之element元素对象

在HTML DOM中&#xff0c;elment对象表示HTML与纳素&#xff0c;可以包含的节点类型有元素u节点、文本节点、注释节点。它们有响应的属性和方法&#xff0c;有很多都是我们之前用过的。 一、element对象属性 1、attributes 2、childNodes 3、className 4、clientWidth、of…

【大厂AI课学习笔记】1.1.4 学科和学习路径

一、8大学科 特点是特点 &#xff1a;厚基础、重交叉、宽口径。 八大学科分别是&#xff1a;数学与统计、科学与工程、计算机科学与技术、人工智能核心、认知与神经科学、先进机器人技术、人工智能工具与平台。 每个学科&#xff0c;又向下延伸。 MORE: AI&#xff0c;即人…

【DDD】学习笔记-限界上下文的控制力

引入限界上下文的目的&#xff0c;不在于如何划分&#xff0c;而在于如何控制边界。因此&#xff0c;我们就需要将对限界上下文的关注转移到对控制边界的理解。显然&#xff0c;对应于统一语言&#xff0c;限界上下文是语言的边界&#xff0c;对于领域模型&#xff0c;限界上下…

muduo网络库剖析——事件循环线程池EventLoopThreadPool类

muduo网络库剖析——线程Thread类 前情从muduo到my_muduo 概要框架与细节成员函数使用方法 源码结尾 前情 从muduo到my_muduo 作为一个宏大的、功能健全的muduo库&#xff0c;考虑的肯定是众多情况是否可以高效满足&#xff1b;而作为学习者&#xff0c;我们需要抽取其中的精…

Spring结合工厂模式

学习设计模式&#xff0c;不要进入一个误区生搬硬套&#xff0c;它是一种编程思想&#xff0c;结合实际使用&#xff0c;往往设计模式是混合使用的 工厂模式 核心本质&#xff1a;使用工厂统一管理对象的创建&#xff0c;将调用者跟实现类解耦 我这里使用Spring容器的支持&am…

latent-diffusion model环境配置--我转载的

latent-diffusion model环境配置&#xff0c;这可能是你能够找到的最细的博客了_latent diffusion model 训练 autoencoder-CSDN博客 前言 最近在研究diffusion模型&#xff0c;并对目前最火的stable-diffusion模型很感兴趣&#xff0c;又因为stable-diffusion是一种latent-di…

【QT+QGIS跨平台编译】之十五:【libTiff+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、libTiff介绍二、文件下载三、文件分析四、pro文件五、编译实践一、libTiff介绍 libTiff是一个用于处理TIFF图像文件格式的开源软件库。 TIFF(Tagged Image File Format)是一种灵活且广泛支持的图像文件格式,常用于存储照片和其他高质量图像。libTiff提供了一套…

Qt QPlainTextEdit高亮显示当前行

Qt QPlainTextEdit高亮显示当前行 文章目录 Qt QPlainTextEdit高亮显示当前行摘要错误的代码正确的代码QTextEdit::ExtraSelection 关键字&#xff1a; Qt、 QPlainTextEdit、 QTextBlock、 ExtraSelection、 GPT 摘要 今天要在说一下GPT&#xff0c;当下如果你还不会用G…

STM32读取MPU6050数据并通过角度值控制舵机运动(STM32、GY-521 MPU6050、SG90舵机、MG946舵机)

通过STM32F103C8T6读取MPU6050数据控制舵机运动&#xff08;STM32、GY-521 MPU6050、SG90舵机、MG946舵机&#xff09; 最终现象一、MPU6050数据读取二、舵机控制原理①什么是PWM&#xff1f;②STM32F103C8T6如何生成PWM&#xff1f;③控制舵机需要什么样的PWM波&#xff1f; 三…

qemu调试kernel启动(从第一行汇编开始)

一、背景 大部分qemu调试kernel 都是讲解从start_kernel开始设置断点&#xff0c;然后开启调试&#xff1b; 但是我们熟悉linux启动流程的伙伴肯定知道&#xff0c;在start_kernel之前还有一段汇编&#xff0c;包括初始化页表及mmu等操作&#xff0c; 这部分如何调试呢&#x…

cocos添加节点事件的3种方式

我们以button为例来说明一下cocos怎样为节点添加事件&#xff1a; 直接通过cocos熟悉检查器绑定 添加事件脚本 import { _decorator, Component, Node, input, Input, Button, EventKeyboard } from cc; const { ccclass, property } _decorator;ccclass(Attack) export cla…

【vue】图片加载骨架

一、前言 在网速较低或者网站的服务器宽带只有几MB的情况下&#xff0c;网页中的图片加载时&#xff0c;要么空白&#xff0c;要么像打印机一样一行一行地“扫描”出来&#xff0c;为了提升用户体验&#xff0c;可以给图片标签外加一层骨架。 无骨架 有骨架 二、详细设计 每张…

无人机在三维空间中的转动问题

前提 这篇博客是对最近一个有关无人机拍摄图像项目中所学到的新知识的一个总结&#xff0c;比较杂乱&#xff0c;没有固定的写作顺序。 无人机坐标系旋转问题 上图是无人机坐标系&#xff0c;绕x轴是翻滚(Roll)&#xff0c;绕y轴是俯仰(Pitch)&#xff0c;绕z轴是偏航(Yaw)。…

sqli-labs第一关

1.判断是否存在注入&#xff0c;注入是字符型还是数字型? ?id1 and 11 ?id1 and 12 因为输入and 11与and 12 回显正常&#xff0c;所以该地方不是数字型。 ?id1 ?id1-- 输入单引号后报错&#xff0c;在单引号后添加--恢复正常&#xff0c;说明存在字符注入 2.猜解SQL查…

Spark Exchange节点和Partitioning

​Exchange 在explain时&#xff0c;常看到Exchange节点&#xff0c;这个节点其实就是发生了数据交换 此图片来自于网络截取 BroadcastExchangeExec 主要是用来广播的 ShuffleExchangeExec 里面决定了数据分布的方式和采用哪种shuffle 在这里可以看到好几种不同的分区器 shuf…

Windows11搭建GPU版本PyTorch环境详细过程

Anaconda安装 https://www.anaconda.com/ Anaconda: 中文大蟒蛇&#xff0c;是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包及其依赖项。从官网下载Setup&#xff1a;点击安装&#xff0c;之后勾选上可以方便在普通命令行cmd和PowerShell中使用…

聊聊Git合并和变基

一、 Git Merge 合并策略 1.1 Fast-Forward Merge&#xff08;快进式合并&#xff09; //在分支1下操作&#xff0c;会将分支1合并到分支2中 git merge <分支2>最简单的合并算法&#xff0c;它是在一条不分叉的两个分支之间进行合并。快进式合并是默认的合并行为&#…

微信小程序wx.getRealtimeLogManager无法查看log内容

解决方案&#xff1a; 首先&#xff0c;检查在we分析是否启用实时日志&#xff0c;入口如下&#xff1a; 其次&#xff0c;检查基本语法是否正确&#xff0c;参考如下&#xff1a; var logger wx.getRealtimeLogManager() logger.error("error message") 最后&a…