前沿:撰写博客的目的是为了再刷时回顾和进一步完善,其次才是以教为学,所以如果有些博客写的较简陋,是为了保持进度不得已而为之,还请大家多多见谅。
预:看到题目后的思路和实现的代码。
见:参考答案展示。
感思:对比答案后的思考,与之前做过的题目是否有关联。
行:
(1)对于没做出来的题目,阅读答案后重新做一遍;
(2)下次做题可以尝试改善的方向;
(3)有助于理解的相关的题目
优先级:做题进度>学习&总结>默写回顾>做题数量
1.题目回顾
2.摆动序列(重难点)
题目链接:376. 摆动序列
2.1思路:
如何想到要使用贪心?
能够由局部最优→全局最优,并且举不出反例则可尝试贪心,若10分钟思路不清晰则可先跳过。
- 贪心题目无迹可寻,若思考一会想不出来则证明挺难的,则可选择先做其他题目。
摆动→峰值数组合即最长子序列
峰值间的最长子序列就是去除中间的单调坡度,就是局部最优。
将所有峰值间中间的坡度都去掉,剩余峰值间的两端点即局部最优→全局最优。
- 要保证两端点的位置正确性,即只在找到摆动序列时才更新上个差值点。
首元素处理
第一个元素默认为峰值,并为了判断条件一致性,为了创建新的第一段前的差值,在首部添加与首元素同值的元素,创建值为0的前段差值,便于将首个子集加入序列。
因为首个子集要加入序列,并且preDiff初始值=0,所以判断条件中preDiff要允许等于0,那么curDiff就不能等于0,否则将没有峰值→不摆动点
保证两端点的位置正确性:避免平坡bug
preDiff = curDiff要写在if判断里面,即实现前面说的只在找到摆动序列时才更新上个差值点。
将preDiff = curDiff写在if判断外面,则每次自动更新preDiff,那么就会峰值间的左端点就是不断移动的,那么就无法保证当条件满足时取的是两端端点。
无法保证当前条件满足时取的是两端端点,为什么会数量有误呢?
因为之前便于处理两端默认了初始preDiff为0,所以判断条件中允许preDiff == 0的。
那么在坡度单调变化中若出现平坡的情况:
因为逻辑是每次循环都令preDiff = curDiff,此时preDiff = 0,则会导致该情况可能会被认为是峰值。
毛毛鱼老师:
“需要注意的是 0 的处理 preDiff在上一次峰值出现后为正值,而如果一直随着curDiff变化在中间就会出现0值,再次出现正数坡度时就会产生峰值计数,但摆动序列是没有出现的”
class Solution {
public int wiggleMaxLength(int[] nums) {
int curDiff = 0;
int preDiff = 0;
int count = 1;
for(int i = 1;i < nums.length;i++){
curDiff = nums[i] - nums[i-1];
if((curDiff > 0 && preDiff <= 0)||(curDiff < 0 && preDiff >= 0)){
count++;
preDiff = curDiff;
}
}
return count;
}
}
2.最大子序和
题目链接:53. 最大子序和
思路
因只需要获得最大和,不需要存储路径,所以当sum = 0时直接重新开始索引;
如果所有值都是负数的情况是否仍然适用?
- 所以是赋值,先与sum比较大小,最后再判断是否重新开始索引。
- 保证了若都是负值仍能够将较小的负值存储。
class Solution {
public int maxSubArray(int[] nums) {
int sum = 0;
int max = nums[0];
for(int i = 0;i < nums.length;i++){
sum += nums[i];
if(sum > max){
max = sum;
}
// max = max > sum?max:sum;
// max = Math.max(sum,max);
if(sum < 0){
sum = 0;
}
}
return max;
}
}
3.分发饼干
题目链接:455.分发饼干
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int index = 0;
int count = 0;
for(int i = 0;i < g.length;i++){
while(index < s.length){
if(s[index] >= g[i]){
count++;
index++;
break;
}else{
index++;
}
}
}
return count;
}
}