代码随想录算法训练营第三十一天 | LeetCode 455. 分发饼干、376. 摆动序列、53. 最大子数组和
文章链接:分发饼干 摆动序列 最大子数组和
视频链接:分发饼干 摆动序列 最大子数组和
目录
代码随想录算法训练营第三十一天 | LeetCode 455. 分发饼干、376. 摆动序列、53. 最大子数组和
1. 贪心算法理论基础
1.1 什么是贪心
1.2 什么时候用贪心
1.3 贪心一般解题步骤
2. LeetCode 455. 分发饼干
2.1 思路
2.2 代码
3. LeetCode 376. 摆动序列
3.1 思路
3.2 代码
4. LeetCode 53. 最大子数组和
4.1 思路
4.2 代码
1. 贪心算法理论基础
1.1 什么是贪心
贪心的本质是选择每一阶段的局部最优,从而达到全局最优。
1.2 什么时候用贪心
说实话贪心算法并没有固定的套路。所以唯一的难点就是如何通过局部最优,推出整体最优。
那么如何能看出局部最优是否能推出整体最优呢?有没有什么固定策略或者套路呢?也没有!靠自己手动模拟,如果模拟可行,就可以试一试贪心策略,如果不可行,可能需要动态规划。
如何验证可不可以用贪心算法呢?最好用的策略就是举反例,如果想不到反例,那么就试一试贪心吧。
1.3 贪心一般解题步骤
- 将问题分解为若干个子问题
- 找出适合的贪心策略
- 求解每一个子问题的最优解
- 将局部最优解堆叠成全局最优解
做题的时候,只要想清楚 局部最优 是什么,如果推导出全局最优,其实就够了。
贪心没有套路,说白了就是常识性推导加上举反例。
2. LeetCode 455. 分发饼干
2.1 思路
2.2 代码
//
class Solution {
// 思路1:优先考虑饼干,小饼干先喂饱小胃口
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int start = 0;
int count = 0;
for (int i = 0; i < s.length && start < g.length; i++) {
if (s[i] >= g[start]) {
start++;
count++;
}
}
return count;
}
}
3. LeetCode 376. 摆动序列
3.1 思路
3.2 代码
//
class Solution {
public int wiggleMaxLength(int[] nums) {
if (nums.length <= 1) {
return nums.length;
}
//当前差值
int curDiff = 0;
//上一个差值
int preDiff = 0;
int count = 1;
for (int i = 1; i < nums.length; i++) {
//得到当前差值
curDiff = nums[i] - nums[i - 1];
//如果当前差值和上一个差值为一正一负
//等于0的情况表示初始时的preDiff
if ((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)) {
count++;
preDiff = curDiff;
}
}
return count;
}
}
4. LeetCode 53. 最大子数组和
4.1 思路
-
题目是给一个数组求最大连续子数组的和,注意是要求连续的。连续和+=nums[i]
-
局部最优:如果连续和在某个位置后是负数,如果还+=nums[i]只会让nums[i]变小,与其继续要前面的连续和,不如直接让连续和变为0再重新+=nums[i],重新开始遍历。因此局部最优就是如果求解连续和时连续和为负数,直接抛弃它,因为只会拖累我们的总和
-
全局最优:在数组中找到了最大连续子数组的和。从这个局部最优好像可以推出全局最优,而且找不到明显的反例反驳这个想法,因此可以试一下这个贪心思路
-
注意:我们是当连续和为负数时才将连续和置为0重新开始遍历,而不是遇到数组中的一个负数就置为0,因为加了这个负数连续和还可能是负数
-
定义个result记录最终结果最大值,初始化为Integer.MIN_VALUE。定义个count记录连续和。result就是用count更新为最大的结果
-
for(int i=0; i<nums.length; i++),在循环中,count+=nums[i],if(count>result),result=count就更新为最新的最大值。if(count<0),就把count=0重新开始遍历。最后return result就行了
4.2 代码
//
class Solution {
public int maxSubArray(int[] nums) {
if (nums.length == 1){
return nums[0];
}
int sum = Integer.MIN_VALUE;
int count = 0;
for (int i = 0; i < nums.length; i++){
count += nums[i];
sum = Math.max(sum, count); // 取区间累计的最大值(相当于不断确定最大子序终止位置)
if (count <= 0){
count = 0; // 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和
}
}
return sum;
}
}