python贪心算法

article/2025/9/12 19:29:10

文章目录

  • 贪心算法
    • 1、分发饼干问题(力扣455)
    • 2、无重叠区间(力扣435)
    • 3、分发糖果(力扣135)
    • 4、种花问题(力扣605)
    • 5、用最少数量的箭引爆气球(力扣452)
    • 6、划分字母区间(力扣763)
    • 7、买卖股票的最佳时机(力扣122)
    • 8、根据身高重建队列(力扣406)
    • 9、非递减数列(力扣665)

贪心算法

1、贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择,就能得到问题的答案。
2、贪心算法需要充分挖掘题目中条件,没有固定的模式,解决有贪心算法需要一定的直觉和经验。
3、贪心算法不是对所有问题都能得到整体最优解。能使用贪心算法解决的问题具有 无后效性,即某阶段状态一旦确定,就不收后阶段决策的影响

1、分发饼干问题(力扣455)

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

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

> 示例:

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

def hand_cookies(g:list, s:list):  # g-->胃口,s-->饼干尺寸g.sort()   # 将胃口值和并饼干尺寸按升序排序s.sort()child, cookie = 0, 0ans = 0while child < len(g) and cookie < len(s):if g[child] <= s[cookie]:  # 如果剩下的最小的饼干能满足剩下胃口最小的孩子ans += 1child += 1   # 移到下一个孩子cookie += 1   # 满足当前胃口,该饼干就已分配,到下一个;没满足当前胃口,此饼干作废,也到下一个饼干return ans

思路分析
1、if g[child] <= s[cookie]: child += 1 # 如果剩下的最小的饼干能满足剩下胃口最小的孩子,此孩子得到满足,轮到下一个孩子
2、cookie += 1 # 无论当前饼干是否满足,都移动到下一个

2、无重叠区间(力扣435)

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

示例 1:

输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3]后,剩下的区间没有重叠。

示例 2:

输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2]
来使剩下的区间没有重叠。

def eraseOverlapInterval(intervals):if not intervals:     # 空区间return 0# 将区间按结束值排序。因为区间结束越早,留给后面区间的空间越多,越有可能得到最多数量的无重复区间intervals = sorted(intervals,key=lambda x : x[1])ans = 0end = intervals[0][1]    # 初始化end为第一个元素的end值for i in range(1,len(intervals)):# 如果当前起始值< 前一个的end值,那么当前区间会被踢剔除。为什么一定剔除这个呢?有没有可能剔除的时此区间之后的?# ---不会,因为当前区间时后面区间中结束值最小的。if end > intervals[i][0]:ans += 1else:end = intervals[i][1]return ans

3、分发糖果(力扣135)

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
1)每个孩子至少分配到 1 个糖果。
2)相邻两个孩子评分更高的孩子会获得更多的糖果。
3)请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。

示例 1

输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。

示例 2

输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。

 def candy(ratings):k = len(ratings)ans = [1]*kfor i in range(1,k):if ratings[i] > ratings[i-1]:    # 右比左大ans[i] = ans[i-1] + 1for i in range(k-2,-1,-1):if ratings[i] > ratings[i+1]:    # 左比右大ans[i] = max(ans[i+1]+1, ans[i])return sum(ans)

思路分析
先从左往右遍历,逐步保证,右边比左边分数高的,获得更多糖果。再从左往右遍历。

ans[i] = max(ans[i+1]+1, ans[i])

这里注意,要取最大值。因为有可能,左边已经比右边大了

4、种花问题(力扣605)

假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false。

示例

输入:flowerbed = [1,0,0,0,1], n = 1 输出:true

def canPlaceFlower(flowerbed: List[int],n:int) -> bool:flowerbed = [0] + flowerbed + [0]count = 0for i in range(1,len(flowerbed)-1):if flowerbed[i-1] == flowerbed[i] == flowerbed[i+1]:flowerbed[i] = 1count += 1if count >= n:return Truereturn False

思路分析
1、flowerbed = [0] + flowerbed + [0]
这里是为了排除边界情况的影响

5、用最少数量的箭引爆气球(力扣452)

在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。

一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend,且满足 xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。
弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。

给你一个数组 points ,其中 points [i] = [xstart,xend] ,返回引爆所有气球所必须射出的最小弓箭数。

示例 :

输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:对于该样例,x = 6 可以射爆[2,8],[1,6] 两个气球,以及 x = 11 射爆另外两个气球

def findMinArrowShots(points:List[List[Int]])-> int:if not points:return 0points = sorted(points, key=lambda x: x[1])ans = 1end = point[0][1]for i in range(1,len(points)):if points[i][0] > end:ans += 1end = points[i][1]return ans

6、划分字母区间(力扣763)

字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。

示例:

输入:S = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释:划分结果为 “ababcbaca”,“defegde”, “hijhklij”。 每个字母最多出现在一个片段中。

【思路】:先把每个字母出现的最后的位置存储起来,再遍历字符串

def partitionLabels(s):dict_ = {}for i in range(len(s)):   # 存取每个字母出现的最大索引位置dict[s[i]] = ians = []start = 0   # 要存取的是字符串片段的长度,故需要end,start两个指针end = dict_[s[0]]for i in range(len(s)):if i < end:end = max(dict_[s[i+1]], end)else:    # i >= endans.append(end - start + 1)if i+1 < len(s):end = dict_[s[i+1]]start = i+1return ans

7、买卖股票的最佳时机(力扣122)

给定一个数组 prices ,其中 prices[i] 表示股票第 i 天的价格。
在每一天,你可能会决定购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以购买它,然后在 同一天 出售。
返回 你能获得的 最大 利润 。

示例:

输入: prices = [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3

def maxProfit(self, prices):ans = 0for i in range(1, len(prices)):if prices[i] > prices[i-1]:ans += prices[i] - prices[i-1]return ans

思路分析
1、每次保证当前解为局部最优解,从而保证得到的解是整体最优
贪心算法
2、遍历从1开始,一次比较当天与前一天利润。

8、根据身高重建队列(力扣406)

假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。
请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

示例:

输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
输出:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
解释:
编号为 0 的人身高为 5 ,没有身高更高或者相同的人排在他前面。
编号为 1 的人身高为 7 ,没有身高更高或者相同的人排在他前面。
编号为 2 的人身高为 5 ,有 2 个身高更高或者相同的人排在他前面,即编号为 0 和 1 的人。
编号为 3 的人身高为 6 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
编号为 4 的人身高为 4 ,有 4 个身高更高或者相同的人排在他前面,即编号为 0、1、2、3 的人。
编号为 5 的人身高为 7 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
因此 [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] 是重新构造后的队列。


def reconstructQueue(people):people = sorted(people, key = lambda x: (-x[0],x[1]))ans = []for item in people:ans.insert(item[1],item)return ans

思路分析
1、因为条件是从高往低,那么我们要先固定高的,再来插入矮的
2、创建ans,从高往低排列,身高相同时,只需要将该身高插入列表对应的位置即可。对应位置几位item[1]

9、非递减数列(力扣665)

给你一个长度为 n 的整数数组 nums ,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。
我们是这样定义一个非递减数列的: 对于数组中任意的 i (0 <= i <= n-2),总满足 nums[i] <= nums[i + 1]。

示例:

输入: nums = [4,2,3]
输出: true
解释: 你可以通过把第一个 4 变成 1 来使得它成为一个非递减数列。

def checkPossibility(nums):count = 0for i in range(1,len(nums)):if nums[i] < nums[i-1]:count += 1    # 一定要调if nums[i] >= nums[i-2] or i == 1:nums[i-1] = nums[i]else: nums[i] = nums[i-1]if count >= 2:return Falsereturn True

思路分析
要保证整个递增,则只需要保证每三个连续的元素是递增的即可。
因为之多改变一个元素,我们初始化一个count用于记录改变的次数。

只移动一个元素,由以上三种关系。
1)nums[i-2] < nums[i],这时,看上去,我们选择将nums[i-1] = nums[i]或者nums[i] = nums[i-2]似乎都是可以的。但是,我们从左往右遍历,前面的元素值越小,留给后面的元素的范围就越大,就越有可能满足“非递减数列”的要求。因此,这种情况,我们应该令nums[i-1] = nums[i]

2)nums[i-2] >nums[i],这种情况我们只能让nums[i] = nums[i-1],因为只有这样满足要求

3)边界情况分析:因为是从左往右去元素,我们只需要考虑左边界。
即只用考虑nums[0] > nums[1]的情况,因为要尽可能给后面的元素更大的范围,所以我们选择将值大的调小,与第一种情况1)道理相同。
反例:nums = [4,1,2,3],就只能把nums[0]调小,使其与nums[1]相等。


http://chatgpt.dhexx.cn/article/APSwa49v.shtml

相关文章

算法-贪心算法

贪心算法 基本概念算法思想贪心算法就像周六晚上的动画片一样可遇不可求贪心解题步骤序列问题53. 最大子数组和 跳跃游戏55. 跳跃游戏跳跃游戏 II 分发糖果 基本概念 贪心算法又称贪婪算法&#xff0c;在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。换句话说&am…

三大算法之三:贪心算法及其例题详解

目录 零.前言 1.区分贪心算法和动态规划 1.动态规划 2.贪心算法 3.共通点 2.贪心算法得到最优解的条件 1.具有优化子结构 2.具有贪心选择性 3.任务安排问题 1.问题定义 2.优化子结构 3.证明贪心选择性 4.总结 4.哈夫曼编码问题 1.问题定义 2.优化子结构 3.贪心…

一看就懂的贪心算法

如何理解贪心算法 我们先看一个例子 假设有一个可以容纳100kg物品的背包&#xff0c;背包可以装各种物品&#xff0c;我们有以下五种豆子&#xff0c;每种豆子的重量和总价值各不相同。为了让背包中所装物品的总价值最大&#xff0c;我们如何选择在背包中装哪些豆子&#xff…

从零开始学贪心算法

本文在写作过程中参考了大量资料&#xff0c;不能一一列举&#xff0c;还请见谅。 贪心算法的定义&#xff1a; 贪心算法是指在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。也就是说&#xff0c;不从整体最优上加以考虑&#xff0c;只做出在某种意义上的局部最优…

如何用wireshark过滤媒体流

进入媒体开发领域的同行来说&#xff0c;一般都会遇到媒体流过滤的问题。那么如何进行媒体流过滤呢&#xff1f; 首先是在媒体服务器的网卡上抓包。其次是获取到通话SIP信令的callid。并根据callid查到sip信令中SDP的IP和PORT。然后用callid及ip和port进行过滤&#xff0c;如果…

WireShark过滤器应用

在工作中我们常会用到wireshark抓取数据包进行分析&#xff0c;当使用wireshark默认设置时&#xff0c;会捕获到大量冗余的数据包&#xff0c;如果没有过滤器过滤&#xff0c;我们很难找到自己想要抓取的数据&#xff0c;这个时候就需要用到wireshark的过滤器来过滤&#xff0c…

Wireshark过滤器写法总结

目录 Wireshark提供了两种过滤器&#xff1a; 1、捕获过滤器 2、显示过滤器 过滤器具体写法 1、显示过滤器写法 1、过滤值比较符号及表达式之间的组合 2、针对ip的过滤 3、针对协议的过滤 4、针对端口的过滤&#xff08;视传输协议而定&#xff09; 5、针对长度和内…

Wireshark 过滤器使用

捕获过滤器&#xff1a; 在抓包之前就设定好过滤条件&#xff0c;然后只抓取符合条件的数据包。 显示过滤器&#xff1a; 在已捕获的数据包集合中设置过滤条件&#xff0c;隐藏不想显示的数据包&#xff0c;只显示符合条件的数据包。 过滤器比较符号 过滤ip和mac地址 ip 改成…

wireshark过滤规则详解

过滤器有两种&#xff1a; 一种是显示过滤器&#xff0c;就是主界面上那个&#xff0c;用来在捕获的记录中找到所需要的记录 一种是捕获过滤器&#xff0c;用来过滤捕获的封包&#xff0c;以免捕获太多的记录。 在Capture -> Capture Filters 中设置 保存过滤&#xff0c…

wireshark 过滤器规则

1、过滤 IP 如来源 IP 或目标 IP。 例子:ip.src eq 192.168.1.107 or ip.dst eq 192.168.1.107 或者ip.addr eq 192.168.1.107 // 都能显示来源 IP 和目标 IP 2、过滤端口 例子: tcp.port eq 80 // 不管端口是来源的还是目标的都显示 tcp.port 80 tcp.port eq 2722 tcp.…

Wireshark过滤器语法

1.官网地址 点击进入 2.捕获过滤器 使用捕获过滤器Wireshark只捕获满足过滤器条件的数据包进来。捕获过滤器采用BPF语法表达式&#xff0c;表达式由如下及部分组成: Dir 指明传输方向是前往还是来自 例如&#xff1a;src、dst Type 指出名字或数字所代表的意&#xff0c;例如…

wireshark过滤telnet

ip.addr172.16.xxx.xxx && tcp.port8080 telnet 端口可以换。可以是23也可以是任意

wireshark过滤器

1、几种条件操作符 eq 等于 ip.addr 192.168.0.1 ip.addr eq 192.168.0.1 ! ne 不等于 !ip.addr192.168.0.1 ip.addr! 192.168.0.1 ip.addr ne 192.168.0.1 > gt 大于 frame.len>64 frame.len gt 64 < lt 小于 frame.le…

Wireshark抓包及常用过滤方法

一、抓包 实际遇到组件服务间的报错问题时&#xff0c;通过日志无法快速看出原因&#xff0c;可通过抓包的方式来快速查看接口返回信息及错误提示&#xff0c;使用如下命令可实现对某个端口进行抓包&#xff1a; tcpdump -i any -w /opt/xxx.pcap tcp port 8150 # 8150为调用…

Wireshark 实用篇:Wireshark 抓包常用过滤命令

目录 前言 正文 一、根据 IP 地址过滤 二、根据端口过滤 三、根据协议过滤 四、根据 Payload Type 条件过滤 五、根据组合条件过滤 六、实例分析 前言 使用 Wireshark 工具进行网络抓包属于研发人员的基础技能&#xff0c;如果你还不了解&#xff0c;建议从现在开始…

Wireshark常用过滤使用方法

过滤源ip、目的ip。 在wireshark的过滤规则框Filter中输入过滤条件。如查找目的地址为192.168.101.8的包&#xff0c;ip.dst192.168.101.8&#xff1b;查找源地址为ip.src1.1.1.1 端口过滤。 如过滤80端口&#xff0c;在Filter中输入&#xff0c;tcp.port80&#xff0c;这条规…

HTML如何返回上一页

<a href"<a href"javascript :history.back(-1)">返回上一页</a>或 <a href"javascript :;" onClick"javascript :history.back(-1);">返回上一页</a>如果是用按钮做的话就是&#xff1a; <input type&quo…

JSP开发--MVC模式(三)

MVC&#xff08;Model-View-Controller&#xff09;模式&#xff0c;即模型-视图-控制器模式MVC1和MVC2模式JSPJavaBeanServlet实现MVC 一&#xff1a;MVC&#xff08;Model-View-Controller&#xff09;模式 MVC模式把交互系统的组成分解成模型&#xff08;Model&#xff09;…

MVC模式概述

一、MVC模式简介 1.1 MVC概念 首先我们需要知道MVC模式并不是javaweb项目中独有的&#xff0c;MVC是一种软件工程中的一种设计模式&#xff0c;把软件系统分为三个基本部分&#xff1a;模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和控制器&#xf…

python-设计模式-MVC模式

概述 mvc模式的思想就是分层&#xff0c;将每个关注点的问题放在不同的层上进行解决。该模式符合SOC&#xff08;关注点分离&#xff09;原则&#xff0c;一般会分为数据访问层&#xff0c;业务逻辑层&#xff0c;表示层。 数据访问层&#xff1a;处理和数据的交互&#xff0…