题干
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 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.
解题思路
这道题的思路用到了贪心算法,在具体阐述之前,让我们看看何为贪心算法。
贪心算法的本质是选择每一阶段的局部最优,从而达到全局最优。
比如从一叠钞票中选取10张,目标是拿最多的钱,那么每次策略就是拿最高金额的纸币,从而达到全局最优。
如何判断这道题目能够使用贪心算法?
动手模拟,举反例,如果没有反例就可以使用。
我们的思路是每次给饼干都尽可能把小饼干喂给胃口小的小孩,充分利用资源。
我们对饼干数组和胃口数组都进行从小到大的排序
本题遍历孩子和饼干的视角都可以,但是饼干的时间复杂度更低。
当我们用孩子遍历时,视角是每遍历一个孩子,不停往更大的饼干找,直到饼干大于等于孩子的胃口。当饼干使用完了,就返回值。 注意不需要建立变量来记录投喂数,孩子的索引就代表投喂数
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
int i = 0;
//对饼干大小数组排序
sort(s.begin(),s.end());
sort(g.begin(),g.end());
int j = 0;
//遍历孩子
for(; i < g.size(); i++){
//从最小的饼干开始给
while(j < s.size() && s[j] < g[i]){
j++;
}
if(j == s.size()){
return i;
}
j++;
}
return i;
}
};
用饼干遍历的做法类似双指针,用到了两个索引。但不是严格意义双指针,因为双指针的两个索引是在同一个数组。这里只是用到了类似的思想
快指针移动寻找可以使用的饼干。
慢指针指向未吃饭孩子中胃口最小的孩子,只有饼干大小大于孩子胃口,慢指针才会指向下一个孩子
循环的本质就是索引的更新,就关键的就是索引。
当我们的判断条件中有存在会改变的量,就需要格外注意,添加限制条件,避免数组越界等问题
数组越界条件书写的顺序要注意,要在可能发生数组越界的地方的前面。
完整代码如下
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
int index = 0;//索引
//从小到大排序两个数组
sort(g.begin(),g.end());
sort(s.begin(),s.end());
for(int j = 0; j < s.size(); j++){//饼干遍历
//避免index的值超过数组边界,造成数组越界
if(index < g.size() && s[j] >= g[index]){
index++;
}
}
return index;
}
};