目录
代码随想录算法训练营第三十一天 | LeetCode 455. 分发饼干、376. 摆动序列、53. 最大子数组和
贪心的本质是选择每一阶段的局部最优,从而达到全局最优。
说实话贪心算法并没有固定的套路。所以唯一的难点就是如何通过局部最优,推出整体最优。
那么如何能看出局部最优是否能推出整体最优呢?有没有什么固定策略或者套路呢?也没有!靠自己手动模拟,如果模拟可行,就可以试一试贪心策略,如果不可行,可能需要动态规划。
如何验证可不可以用贪心算法呢?最好用的策略就是举反例,如果想不到反例,那么就试一试贪心吧。
做题的时候,只要想清楚 局部最优 是什么,如果推导出全局最优,其实就够了。
贪心没有套路,说白了就是常识性推导加上举反例。


- //
- 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;
- }
- }




- //
- 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;
- }
- }
题目是给一个数组求最大连续子数组的和,注意是要求连续的。连续和+=nums[i]
局部最优:如果连续和在某个位置后是负数,如果还+=nums[i]只会让nums[i]变小,与其继续要前面的连续和,不如直接让连续和变为0再重新+=nums[i],重新开始遍历。因此局部最优就是如果求解连续和时连续和为负数,直接抛弃它,因为只会拖累我们的总和
全局最优:在数组中找到了最大连续子数组的和。从这个局部最优好像可以推出全局最优,而且找不到明显的反例反驳这个想法,因此可以试一下这个贪心思路
注意:我们是当连续和为负数时才将连续和置为0重新开始遍历,而不是遇到数组中的一个负数就置为0,因为加了这个负数连续和还可能是负数
定义个result记录最终结果最大值,初始化为Integer.MIN_VALUE。定义个count记录连续和。result就是用count更新为最大的结果
for(int i=0; i
- //
- 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;
- }
- }