代码随想录算法训练营第三十一天|LeetCode455,376,53

代码随想录算法训练营第三十一天|LeetCode455,376,53

Day31

理论基础

贪心最大的难处在于:不知道哪里用了贪心

有的时候题目做出来了,还不知道自己用了贪心。

贪心的本质是选择每一阶段的局部最优,从而达到全局最优

有同学问了如何验证可不可以用贪心算法呢?

最好用的策略就是举反例,如果想不到反例,那么就试一试贪心吧

455.分发饼干 (排序算法的实现)

看到题的想法是按照升序对两个数组进行排序

然后判断满足值g[i]是否小于等于饼干s[j],如果满足条件就将i,j后移,否则,仅仅移动j找一个更大的饼干。

public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int i = 0;
        int j = 0;

        while (i<g.length&&j<s.length){
            if (g[i]<=s[j]){
                i++;
                j++;
            }else if (g[i] > s[j]){
                j++;
            }
        }
        return i;

    }

376.摆动序列 (*)

一点思路都没有

局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值

整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列

局部最优推出全局最优,并举不出反例,那么试试贪心!

本题要考虑三种情况:

  1. 情况一:上下坡中有平坡
  2. 情况二:数组首尾两端
  3. 情况三:单调坡中有平坡
public int wiggleMaxLength(int[] nums) {
        if(nums.length<1){
            return nums.length;
        }

        //当前差值
        int curDiff = 0;
        //前一个差值
        int preDiff = 0;
        //记录峰值个数,默认为序列最右边有一个峰值是为了处理数组只有两个值的情况。
        int result = 1;
        for(int i = 0; i < nums.length - 1;i++){
            //得到当前值
            curDiff = nums[i+1] - nums[i];
            //出现峰值。这里preDiff = 0是考虑出现平坡的时候去除左边的值,以及仅仅有两个数值的情况
            if ((preDiff<=0&&curDiff>0)||(preDiff>=0&&curDiff<0)){
                result++;
                //更新preDiff的时机要注意,只有当出现摆动(峰值)的时候才更新preDiff。这样就处理了在单调过程中出现平坡的问题
                preDiff = curDiff;

            }
        }
        return result;

    }

53.最大子序和

贪心贪的是哪里呢?

如果 -2 1 在一起,计算起点的时候,一定是从1开始计算,因为负数只会拉低总和,这就是贪心贪的地方!

局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。

全局最优:选取最大“连续和”

局部最优的情况下,并记录最大的“连续和”,可以推出全局最优

从代码角度上来讲:遍历nums,从头开始用count累积,如果count一旦加上nums[i]变为负数,那么就应该从nums[i+1]开始从0累积count了,因为已经变为负数的count,只会拖累总和。

这相当于是暴力解法中的不断调整最大子序和区间的起始位置

第一次错误:如果传入的数值全部是负数。

改正:将 result = count > result?count:result;放到count+=nums[i]后,这样可以保证负数也会有正常的返回值。

    public int maxSubArray(int[] nums) {
        int result = Integer.MIN_VALUE;
        int count = 0;
        for (int i = 0; i < nums.length; i++){
            count += nums[i];

            result = count > result?count:result;

            //贪心的地方,如果连续和小于0了,那么加上下一个元素只会变小,所以应该从下一个值开始重新计算count
            if (count < 0){
                count = 0;
            }

        }
        return result;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值