假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 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.
455. 分发饼干 力扣
为了尽可能满足最多数量的孩子,从贪心的角度考虑,应该按照孩子的胃口从小到大的顺序依次满足每个孩子,且对于每个孩子,应该选择可以满足这个孩子的胃口且尺寸最小的饼干。
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个字典,直接排序用原始数据计算即可。
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),