LeetCode 455. 分发饼干
Posted 想名真难
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 455. 分发饼干相关的知识,希望对你有一定的参考价值。
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i
,都有一个胃口值 g[i]
,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j
,都有一个尺寸 s[j]
。如果 s[j] >= g[i]
,我们可以将这个饼干 j
分配给孩子 i
,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
示例 1:
输入: g = [1,2,3], s = [1,1] 输出: 1 解释: 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 所以你应该输出1。
示例 2:
输入: g = [1,2], s = [1,2,3] 输出: 2 解释: 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 你拥有的饼干数量和尺寸都足以让所有孩子满足。 所以你应该输出2.
为了尽可能满足最多数量的孩子,从贪心的角度考虑,应该按照孩子的胃口从小到大的顺序依次满足每个孩子,且对于每个孩子,应该选择可以满足这个孩子的胃口且尺寸最小的饼干。
- 统计出每个胃口的孩子数量
- 统计出饼干大小的数量
- 对胃口和饼干大小做升序排列
- 遍历每个胃口,针对每个胃口处理
- 饼干大小 < 胃口
- 饼干大小调大
- 饼干大小 >= 胃口
- 如果此胃口对应的饼干数量 >= 孩子数,
- 结果 += 孩子数,
- 此胃口剩余的饼干数量 = 饼干数 - 孩子数
- 如果此胃口对应的饼干数量 < 孩子数,
- 剩余待分配的孩子数 = 孩子数 - 此胃口对应的饼干数量
- 把饼干的大小调大,继续匹配,递归调用,直到剩余孩子数量为0,
- 如果此胃口对应的饼干数量 >= 孩子数,
- 饼干大小 < 胃口
- 返回结果
class Solution
var gDic : [Int:Int]!
var sDic : [Int:Int]!
var gKeyArray : [Int]!
var sKeyArray : [Int]!
var gIndex = 0
var sIndex = 0
var result = 0
func findContentChildren(_ g: [Int], _ s: [Int]) -> Int
gDic = [Int:Int]()
sDic = [Int:Int]()
// 以胃口做key, value为这个胃口的人数
for oneG in g
if let count = gDic[oneG]
gDic[oneG] = count + 1
else
gDic[oneG] = 1
// 以饼干大小做key, value为这个大小的饼干数量
for oneS in s
if let count = sDic[oneS]
sDic[oneS] = count + 1
else
sDic[oneS] = 1
// 胃口和饼干都按照从小到大的顺序排列
gKeyArray = gDic.keys.sorted()
sKeyArray = sDic.keys.sorted()
gIndex = 0
sIndex = 0
result = 0
while gIndex < gKeyArray.count && sIndex < sKeyArray.count
// 饼干大小 < 胃口大小, 把饼干大小增加, 直到饼干大小 >= 胃口大小, 或者没有饼干,结束循环
if sKeyArray[sIndex] < gKeyArray[gIndex]
sIndex += 1
else
let studentCount = gDic[gKeyArray[gIndex]]!
self.handleStu(studentCount: studentCount)
return result
// 给学生分配饼干
func handleStu(studentCount : Int)
if studentCount <= 0
return
if sIndex >= sKeyArray.count
return
if let sValue = sDic[sKeyArray[sIndex]]
if sValue >= studentCount
result += studentCount
let leftValue = sValue - studentCount
sDic[sKeyArray[sIndex]] = leftValue
gIndex += 1
else
sDic[sKeyArray[sIndex]] = 0
result += sValue
// 先把sValue个饼干分给同胃口的学生, 剩余待分配的学生数量就是studentCount -= sValue
let leftStudentCount = studentCount - sValue
// sIndex持续往上增加,知道把此胃口的学生都分配完成
sIndex += 1
// 递归调用自己,继续分配,直到剩余学生数量为0或者没有饼干
self.handleStu(studentCount: leftStudentCount)
多次遍历数组+2次排序,总体的时间复杂度为O(N*logN), 需要额外的空间来存字典,空间复杂度为O(N).
虽然通过了所有用例, 但是时间上只超过26% , 可能会有更优的解法.
看了一下题解,改进一下,其实没有必要来维护这2个字典,直接排序用原始数据计算即可。
- 首先还是排序,对胃口和饼干大小做升序排列,比如g=[7,7,8,8,9,9], s = [7,8,9]
- 用2个下标来记录分配到的位置
- 针对每个胃口处理
- 对应的饼干大小 > 胃口大小
- 结果 += 1
- 孩子后移1个, 饼干后移1个
- 对应的饼干大小 < 胃口大小
- 饼干后移1个, 其余不动
- 对应的饼干大小 > 胃口大小
class Solution
func findContentChildren(_ g: [Int], _ s: [Int]) -> Int
// 胃口和饼干都按照从小到大的顺序排列
let gArray = g.sorted()
let sArray = s.sorted()
// 对应数组的下表
var gIndex = 0
var sIndex = 0
// 总的匹配数
var result = 0
while gIndex < gArray.count && sIndex < sArray.count
// 饼干大小 < 胃口大小, 把饼干大小增加
// 饼干大小 >= 胃口大小, 总数+1,饼干后移,学生后移
if sArray[sIndex] < gArray[gIndex]
sIndex += 1
else
sIndex += 1
gIndex += 1
result += 1
return result
改进之后的算法看起来思路也清晰了很多, 代码行数也少了很多, 性能也比第一种提升很大.
跑下用例, 其实时间上就是100%, 只是LeetCode的机器有时快,有时慢,跑完用例的时间不一致导致,由于有排序操作和遍历操作,时间复杂度还是O(N*logN), 空间复杂度O(1),
以上是关于LeetCode 455. 分发饼干的主要内容,如果未能解决你的问题,请参考以下文章