455.分发饼干
题目链接:分发饼干
题目描述:假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子
i
,都有一个胃口值g[i]
,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干j
,都有一个尺寸s[j]
。如果s[j] >= g[i]
,我们可以将这个饼干j
分配给孩子i
,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
解题思想:
为了满足更多的小孩,就不要造成饼干尺寸的浪费。
大尺寸的饼干既可以满足胃口大的孩子也可以满足胃口小的孩子,那么就应该优先满足胃口大的。
这里的局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。可以尝试使用贪心策略,先将饼干数组和小孩数组排序。
然后从后向前遍历小孩数组,用大饼干优先满足胃口大的,并统计满足小孩数量。
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
sort(g.begin(), g.end());
sort(s.begin(), s.end());
int count = 0;
int index = s.size() - 1;
for (int j = g.size() - 1; j >= 0; j--) {
if (index >=0 && s[index] >= g[j]) {
index--;
count++;
}
}
return count;
}
};
也可以优先小饼干满足小胃口,从前向后遍历饼干数组,用小饼干满足小胃口,并统计小孩的数量。
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
sort(g.begin(), g.end());
sort(s.begin(), s.end());
int index = 0;
for (int i = 0; i < s.size();i++) {
if (index < g.size() && s[i] >= g[index]) {
index++;
}
}
return index;
}
};
376. 摆动序列
题目链接:摆动序列
题目描述:如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 **摆动序列 。**第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
- 例如,
[1, 7, 4, 9, 2, 5]
是一个 摆动序列 ,因为差值(6, -3, 5, -7, 3)
是正负交替出现的。- 相反,
[1, 4, 7, 2, 5]
和[1, 7, 4, 5, 5]
不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。
给你一个整数数组
nums
,返回nums
中作为 摆动序列 的 最长子序列的长度 。
解题思想:
局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。
整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列。
在计算是否有峰值的时候,大家知道遍历的下标 i ,计算 prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i]),如果prediff < 0 && curdiff > 0
或者 prediff > 0 && curdiff < 0
此时就有波动就需要统计。
这是我们思考本题的一个大题思路,但本题要考虑三种情况:
- 情况一:上下坡中有平坡
- 情况二:数组首尾两端
- 情况三:单调坡中有平坡
情况一:上下坡中有平坡
例如 [1,2,2,2,1]这样的数组,如图:
它的摇摆序列长度是多少呢? 其实是长度是 3,也就是我们在删除的时候 要不删除左面的三个 2,要不就删除右边的三个 2。
我们记录峰值的条件应该是: (preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)
,为什么这里允许 prediff == 0 ,就是为了删除平坡中的连续元素只保留一个。
情况二:数组首尾两端
所以本题统计峰值的时候,数组最左面和最右面如何统计呢?题目中说了,如果只有两个不同的元素,那摆动序列也是 2。
首元素可以统一为有平坡的情况,即curdiff初始化为0。尾元素一直都计算在摆动序列长度内,count从1开始记数。
情况三:单调坡中有平坡
只需要在这个坡度摆动变化的时候,更新 prediff 就行,这样 prediff 在单调区间有平坡的时候就不会发生变化,造成我们的误判
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
int prediff = 0;
int curdiff;
int count = 1;
for (int i = 0; i < nums.size() - 1; i++) {
curdiff = nums[i + 1] - nums[i];
if ((curdiff > 0 && prediff <= 0) ||
(curdiff < 0 && prediff >= 0)) {
count++;
prediff = curdiff;
}
}
return count;
}
};
53. 最大子序和
题目链接:最大子序和
题目描述:给你一个整数数组
nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。
解题思想:
最笨的解法就是暴力解法,两层for循环,一层确定开始位置,一层确定终止位置。
贪心算法:
局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。
全局最优:选取最大“连续和”
局部最优的情况下,并记录最大的“连续和”,可以推出全局最优。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int sum = 0;
int result = INT32_MIN;
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
if (sum > result)
result = sum;
if (sum <= 0)
sum = 0;
}
return result;
}
};