目录
1. T455:分发饼干
T455:假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
提示:
-
1 <= g.length <= 3 * 104
-
0 <= s.length <= 3 * 104
-
1 <= g[i], s[j] <= 231 - 1
S:本题的思路可分两种:一个是优先用大饼干满足大胃口,另一个是优先用小饼干满足小胃口。
从贪心算法的角度来说,可以分为:
- 局部最优:大(小)满足大(小)胃口;
- 全局最优:尽可能让更多小孩吃到满足胃口的饼干。
1.1 思路1:从大到小
该思路就是先拿着最大的饼干去从最大胃口的孩子开始喂,喂饱之后再开始用小饼干。
C++:
int findContentChildren(vector<int>& g, vector<int>& s) {
sort(g.begin(), g.end());
sort(s.begin(), s.end());
int res = 0;
int index = s.size() - 1;// 饼干数组的下标【🚩试了一下index和i互换,解答错误,尚未想清楚】
for (int i = g.size() - 1; i >= 0; --i) {
// if (s[index] >= g[i]) {// 导致runtime error
if (index >= 0 && s[index] >= g[i]) {
++res;
--index;
}
}
return res;
}
Java:
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int res = 0;
int index = s.length - 1;
for (int i = g.length - 1; i >= 0; --i) {
if (index >= 0 && s[index] >= g[i]) {
--index;
++res;
}
}
return res;
}
1.2 思路2:从小到大
该思路则反过来,先从最小胃口的孩子(出发点与上一种思路不同)开始喂小饼干,喂饱之后再开始喂饱大胃口的孩子
C++:
int findContentChildren(vector<int>& g, vector<int>& s) {
sort(g.begin(), g.end());
sort(s.begin(), s.end());
// int res = 0;
int index = 0;// 胃口数组的下标【这里相当于index和i互换了(相对于版本Ⅰ)】
for (int i = 0; i < s.size(); ++i) {
if (index < g.size() && s[i] >= g[index]) {
// ++res;
++index;
}
}
// return res;
return index;
}
Java:
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int index = 0;
for (int i = 0; i < s.length; ++i) {
if (index < g.length && s[i] >= g[index]) {
++index;
}
}
return index;
}
1.3 思考
-
到最后都没完全想明白一个问题:
-
为什么从大到小index对应饼干数组,从小到大index对应胃口数组,反之就错?
-
-
用从大到小:如果先拿着大胃口去找饼干吃,按照本例会得出结果为0;
-
用从小到大:如果先拿着小饼干去喂,按照本例也会得出结果为0。
2. T376:摆动序列【动规解法暂搁】
T376:如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。
相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。
给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。
提示:
-
1 <= nums.length <= 1000
-
0 <= nums[i] <= 1000
进阶:你能否用 O(n) 时间复杂度完成此题?
S:本题如果真的想着删除或修改元素,那就复杂化了!
从贪心算法的角度来说:
-
局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。
-
整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列。
C++:
int wiggleMaxLength(vector<int>& nums) {
int res = 1;// 记录峰值个数,序列默认序列最右边有一个峰值
int curDiff = 0;
int preDiff = 0;
for (int i = 0; i < nums.size() - 1; ++i) {
curDiff = nums[i + 1] - nums[i];
//如果当前差值和上一个差值为一正一负就算(preDiff等于0表示初始情况)
if ((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)) {
++res;
preDiff = curDiff;
}
}
return res;
}
Java:
public int wiggleMaxLength(int[] nums) {
int res = 1;
int preDiff = 0, curDiff = 0;
for (int i = 1; i < nums.length; ++i) {
curDiff = nums[i] - nums[i - 1];
if ((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)) {
preDiff = curDiff;
++res;
}
}
return res;
}
3. T53:最大子序和【动规暂搁】
T53:给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
提示:
-
1 <= nums.length <= 105
-
-104 <= nums[i] <= 104
S:
3.1 法1、暴力解法(了解即可,超时时间限制)
暴力解法,其实就是把所有可能的连续子数组的元素和全部算出来,在该过程中出现的最大值就是result
C++:
int maxSubArray(vector<int>& nums) {
int res = INT32_MIN;
int count = 0;
for (int i = 0; i < nums.size(); ++i) {// 设置起始位置
count = 0;// 一定要归零!
for (int j = i; j < nums.size(); ++j) {
count += nums[j];
res = res > count ? res : count;// 取区间累计的最大值(相当于不断确定最大子序终止位置)
}
}
return res;
}
-
时间复杂度:O(n^2)
-
空间复杂度:O(1)
3.2 法2、贪心算法
贪心贪的是哪里呢?
如果 -2 1 在一起,计算起点的时候,一定是从1开始计算,因为负数只会拉低总和,这就是贪心贪的地方!
-
局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。
-
全局最优:选取最大“连续和”
局部最优的情况下,并记录最大的“连续和”,可以推出全局最优。
🚩关键在于:不能让“连续和”为负数的时候加上下一个元素,而不是 不让“连续和”加上一个负数。
C++:
int maxSubArray(vector<int>& nums) {
int res = INT32_MIN;
int count = 0;
for (int i = 0; i < nums.size(); ++i) {
count += nums[i];
res = res > count ? res : count;// 取区间累计的最大值(相当于不断确定最大子序终止位置)
if (count <= 0) count = 0;// 🚩重置最大子序起始记录位置(“连续和”为负数的时候立刻放弃)
}
return res;
}
Java:
public int maxSubArray(int[] nums) {
int res = Integer.MIN_VALUE;
int count = 0;
for (int i = 0; i < nums.length; ++i) {
count += nums[i];
res = count > res ? count : res;
if (count <= 0) count = 0;
}
return res;
}