Easy
题目描述
假设你是一位很棒的家长,想要给你的孩子们一些饼干。但是,你应该给每个孩子最多一块饼干。
每个孩子 i 都有一个贪心因子 g[i],这是能让孩子满足的饼干的最小尺寸;每块饼干 j 都有一个尺寸 s[j]。如果 s[j] >= g[i],我们可以将饼干 j 分配给孩子 i,孩子 i 会得到满足。你的目标是最大化满足的孩子数量,并输出最大数量。
示例 1:
输入:g = [1,2,3], s = [1,1]
输出:1
解释:你有 3 个孩子和 2 块饼干。3 个孩子的贪心因子分别是 1、2、3。
虽然你有 2 块饼干,由于它们的尺寸都是 1,你只能让贪心因子是 1 的孩子满足。
所以你应该输出 1。
示例 2:
输入:g = [1,2], s = [1,2,3]
输出:2
解释:你有 2 个孩子和 3 块饼干。2 个孩子的贪心因子分别是 1、2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出 2。
提示:
- 1 <= g.length <= 3 * 10^4
- 0 <= s.length <= 3 * 10^4
- 1 <= g[i], s[j] <= 2^31 - 1
注意: 这个问题与 2410. 玩家和训练师的最大匹配数 相同。
解题思路
这是一道经典的贪心算法题目。要最大化满足的孩子数量,我们应该采用贪心策略:对于每个孩子,尽量给他们能满足其需求的最小饼干。
核心思路如下:
- 排序:将孩子的贪心因子数组 g 和饼干尺寸数组 s 都按升序排序
- 双指针遍历:使用两个指针分别指向孩子数组和饼干数组的当前位置
- 贪心匹配:
- 如果当前饼干能满足当前孩子(s[j] >= g[i]),则匹配成功,满足孩子数加1,两个指针都向前移动
- 如果当前饼干不能满足当前孩子(s[j] < g[i]),则只移动饼干指针,寻找更大的饼干
这种贪心策略的正确性在于:如果一个较小的饼干能满足贪心因子较大的孩子,那么它也一定能满足贪心因子较小的孩子。为了最大化满足的孩子数量,我们应该把小饼干优先分给贪心因子小的孩子,这样能避免浪费。
时间复杂度主要由排序决定,为 O(n log n + m log m),其中 n 和 m 分别是孩子和饼干的数量。
代码实现
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
sort(g.begin(), g.end());
sort(s.begin(), s.end());
int i = 0, j = 0, count = 0;
while (i < g.size() && j < s.size()) {
if (s[j] >= g[i]) {
count++;
i++;
}
j++;
}
return count;
}
};
class Solution:
def findContentChildren(self, g: List[int], s: List[int]) -> int:
g.sort()
s.sort()
i = j = count = 0
while i < len(g) and j < len(s):
if s[j] >= g[i]:
count += 1
i += 1
j += 1
return count
public class Solution {
public int FindContentChildren(int[] g, int[] s) {
Array.Sort(g);
Array.Sort(s);
int i = 0, j = 0, count = 0;
while (i < g.Length && j < s.Length) {
if (s[j] >= g[i]) {
count++;
i++;
}
j++;
}
return count;
}
}
var findContentChildren = function(g, s) {
g.sort((a, b) => a - b);
s.sort((a, b) => a - b);
let i = 0, j = 0, count = 0;
while (i < g.length && j < s.length) {
if (s[j] >= g[i]) {
count++;
i++;
}
j++;
}
return count;
};
复杂度分析
| 复杂度类型 | 值 | 说明 |
|---|---|---|
| 时间复杂度 | O(n log n + m log m) | 其中 n 和 m 分别是孩子和饼干的数量,主要时间消耗在排序上 |
| 空间复杂度 | O(1) | 只使用了常数级别的额外空间 |