分发饼干
题目描述
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 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.
解题思路
- 排序:首先对孩子们的需求数组
g
和饼干的大小数组s
进行排序。这样做的目的是为了能够从需求最大和大小最大的饼干开始匹配,以尽可能满足更多的孩子。 - 从大到小匹配:从需求最大的孩子开始,尝试用最大的饼干去满足他。如果当前最大的饼干可以满足当前孩子的需求,则将该饼干分配给该孩子,并移动到下一个更大的饼干和下一个需求更大的孩子。
- 贪心选择:每次选择当前最大的饼干去满足当前需求最大的孩子,这样可以保证每次选择都是局部最优的,从而达到全局最优的结果。
代码实现
测试地址:https://leetcode.cn/problems/assign-cookies/
class Solution {
public:
int findContentChildren(vector<int> &g, vector<int> &s) {
// 对孩子们的需求和饼干的大小进行排序
sort(g.begin(), g.end());
sort(s.begin(), s.end());
// 初始化饼干的索引为最大值
int index = s.size() - 1;
// 初始化满足的孩子数量为0
int count = 0;
// 从需求最大的孩子开始遍历
for (int i = g.size() - 1; i >= 0; i--) {
// 如果当前饼干可以满足当前孩子的需求
if (index >= 0 && s[index] >= g[i]) {
// 满足的孩子数量加一
count++;
// 使用过的饼干索引减一
index--;
}
}
// 返回满足的孩子数量
return count;
}
};
摆动序列
题目描述
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。 第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
- 例如,
[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 = [1,7,4,9,2,5]
输出:6
解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3) 。
示例 2:
输入:nums = [1,17,5,10,13,15,10,5,16,8]
输出:7
解释:这个序列包含几个长度为 7 摆动序列。
其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。
示例 3:
输入:nums = [1,2,3,4,5,6,7,8,9]
输出:2
解题思路
贪心思路:每次选择形成摆动的相邻元素对,这样可以保证每次选择都是局部最优的,从而达到全局最优的结果。
本题共有三种特殊情况需要处理:
上下坡中有平坡
当数组中存在连续的相同值时,
curdiff
会等于0,此时平坡的长度不会被计入摆动序列的长度中,此时峰值记录的条件为:(preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)
数组首尾两端
当数组元素为2时,为了匹配上面的条件,可以在虚拟一个节点作为作为第一个节点的平坡,然后将count的值初始化为1,因为第一个节点到第二个节点肯定会有一个峰值,从而匹配情况一种提到的:
prediff=0 && cur>0
的情况,count++,摆动序列值为2
单调中有平坡
- 如果是从上述条件中推理,在下面这个情况中是会有3个峰值的,但是实际摆动序列为2,造成这个情况的原因是因为我们实时的更新了 prediff的值,而不是当
curdiff
的符号与prediff
的符号相反时,再进行count++以及更新prediff的操作。
- 如果是从上述条件中推理,在下面这个情况中是会有3个峰值的,但是实际摆动序列为2,造成这个情况的原因是因为我们实时的更新了 prediff的值,而不是当
代码实现
测试地址:https://leetcode.cn/problems/wiggle-subsequence/
class Solution {
public:
int wiggleMaxLength(vector<int> &nums) {
if (nums.size() == 1)
return 1; // 如果数组只有一个元素,则摆动序列的长度为1
int count = 1; // 初始化摆动序列的长度为1
int prediff = 0; // 初始化前一个差值为0
int curdiff = 0; // 初始化当前差值为0
for (int i = 0; i < nums.size() - 1; i++) {
curdiff = nums[i + 1] - nums[i]; // 计算当前差值
// 如果当前差值和前一个差值形成摆动,则更新摆动序列的长度
if ((prediff <= 0 && curdiff > 0) || (prediff >= 0 && curdiff < 0)) {
count++;
prediff = curdiff; // 更新前一个差值
}
}
return count; // 返回摆动序列的长度
}
};
最大子数组和
题目描述
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [5,4,-1,7,8]
输出:23
解题思路
- 初始化:首先初始化最大子序列和
subSum
为最小整数值,确保任何子数组的和都能够更新这个值。同时,初始化当前计算的子序列和tmpSum
为0。 - 遍历数组:遍历数组中的每一个元素,对
tmpSum
进行累加,计算得到当前的子序列和。 - 更新最大子序列和:如果当前子序列和
tmpSum
大于已知的最大子序列和subSum
,那么就更新最大子序列和为当前子序列和。 - 贪心选择:如果当前子序列和
tmpSum
小于等于0,那么就抛弃之前的子序列,因为这些子序列和对于后续的和来说,只会减小总的和,不会增加。因此我们选择从下一个位置重新开始计算子序列和。
代码实现
测试地址:https://leetcode.cn/problems/maximum-subarray/
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int subSum = INT_MIN; // 初始化最大子序列和为最小整数值
int tmpSum = 0; // 初始化当前计算的子序列和为0
for (int i = 0; i < nums.size(); i++) {
tmpSum += nums[i]; // 计算当前子序列和
if (tmpSum > subSum)
subSum = tmpSum; // 如果当前子序列和大于最大子序列和,则更新最大子序列和
if (tmpSum <= 0)
tmpSum = 0; // 如果当前子序列和小于等于0,那么抛弃之前的子序列,从新的位置重新计算子序列和
}
return subSum; // 返回最大子序列和
}
};