分发饼干之 双数组匹配问题 (双指针 or 二分)
文章目录
- 455.分发饼干
- 2410.运动员和训练师的最大匹配数
455.分发饼干
- 思路分析:根据
贪心策略
,肯定是胃口g[i]
匹配大于等于它的最小的饼干s[i]
,同时,还需要考虑,一个饼干只能给一个胃口,所以我们不能重复分配 - 由于涉及到
大小问题
,所以,我们对数组g
和s
都先进行升序排序
二分思路来源
- 如果直接暴力求解,也就是对于孩子胃口
g[i]
,都在饼干数组中,重头开始遍历查找,那么时间复杂度会来到o(n^2)
,肯定是会超时的 - 考虑到我们的目标是对于每一个孩子的胃口
g[i]
找到第一个还没被分配的>=g[i]的s[i]
,所以我们可以使用限制范围二分
进行求解,在这里介绍这个bisect_left(a,x,lo=0,hi=len(a)
,可以通过lo
和hi
对于搜索的范围进行限定,其中总的范围是一个左闭右开的情况[0,len(a))
- 这里有一个提前终止的情况,也就是当较小的
g[i]
都无法找到合适的s[j]
(也就是bisect_left方法返回数组长度),那么我们可以提前终止
import bisect
class Solution:def findContentChildren(self, g: List[int], s: List[int]) -> int:kid = len(g)bin = len(s)ans = 0 g.sort()s.sort()# 二分,但是有范围的二分ans = 0 curleft = 0 for i,c in enumerate(g):index = bisect.bisect_left(s,c,lo=curleft)if index == bin:breakans += 1curleft = index + 1return ans
双指针
- 考虑到暴力的做法的时间复杂度是
o(n^2)
,并且浪费的时间在于一些重复的查找过程,所以我们可以考虑使用双指针
,记录当前的匹配到的孩子的下标,通过对饼干的一次遍历,我们就可以得到最终的结果
- 出发的角度,其实可以使用变量记录当前的孩子,然后遍历饼干,另一种思路是记录当前的饼干,然后遍历孩子。比较之后,发现第一种思路比较好,因为最终孩子的下标就是最终的答案
- 对于双指针的到底使用
cur
变量记录什么,以及枚举孩子还是饼干
,这个是不能搞错的,如何理解?我们的任务是给孩子分饼干,分配的策略是对于每一个孩子分配满足情况的最小的饼干,所以cur
记录的是当前分配到的孩子,为了找到合适的饼干,所以我们需要枚举饼干
class Solution:def findContentChildren(self, g: List[int], s: List[int]) -> int:kid = len(g)bin = len(s)ans = 0 g.sort()s.sort()# 当前孩子的下标curkid = 0 for i,c in enumerate(s):if curkid < kid and g[curkid] <= c :curkid += 1return curkid
2410.运动员和训练师的最大匹配数
2410.运动员和训练师的最大匹配数
- 思路分析:这题和
分发饼干
思路是一样的,当然这里我们的任务是给运动员分配训练师
,所以cur
记录的是当前分配到的运动员的下标,我们需要枚举训练师
class Solution:def matchPlayersAndTrainers(self, players: List[int], trainers: List[int]) -> int:n = len(players)players.sort()trainers.sort()curplayer = 0 for c in trainers:if curplayer < n and players[curplayer] <= c:curplayer+=1return curplayer