代码随想录算法训练营第三十一天| 理论基础 、455.分发饼干 、376. 摆动序列、53. 最大子序和

491.理论基础

  • 链接:代码随想录

  • 解题思路:

    通过局部最优,推出整体最优

image-20230414213904240

  • 如何验证贪心算法的正确性

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

455.分发饼干

大饼干配大胃口

  • 解题思路:
    让饼干不浪费即可
    这里的局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。
//思路一:小饼干喂给小胃口
public int findContentChildren(int[] g, int[] s) {

    int sum = 0;//结果
    int j = 0;

    //排序
    Arrays.sort(g);
    Arrays.sort(s);

    for (int i = 0; i < g.length; i++) {//遍历饼干

        while(j < s.length && s[j] < g[i]){//这个饼干不符合孩子肚量,直到找到符合胃口的
            j++;
        }
        //满足条件
        if(j < s.length){
            sum++;
            j++;
        }
        //超出范围
        if(j == s.length){
            break;
        }
    }

    return sum;
}
// 思路2:优先考虑胃口,先喂饱大胃口
public int findContentChildren(int[] g, int[] s) {
    Arrays.sort(g);
    Arrays.sort(s);
    int count = 0;
    int start = s.length - 1;
    // 遍历胃口
    for (int index = g.length - 1; index >= 0; index--) {
        if(start >= 0 && g[index] <= s[start]) { //优先喂饱大胃口的
            start--;
            count++;
        }
    }
    return count;
}

376. 摆动序列⭐️

摆动序列看一个元素的前后元素的差值的符号,小范围满足,则大范围也满足

  • 解题思路:
    局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。
    **整体最优:**整个序列有最多的局部峰值,从而达到最长摆动序列。
    **贪心:**实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了
    本题设置一个preDiff和curDiff记录操作元素和前后元素的差值
    本题需要注意三点

  • 注意三点

    • 上下坡中有平坡

      image-20230414201846282

    • 数组长度不够,在首尾两端

      image-20230414201950410

    • 单调坡有平坡 —> 多记录冗余值

      image-20230414202508933

*/
    public int wiggleMaxLength(int[] nums) {
    if(nums.length <= 1){
        return nums.length;
    }


    //记录当前差值
    int curDiff = 0;
    //记录先前差值
    int preDiff = 0;//初始值为0,解决数组长度为2的状况

    int res = 1;//记录结果,数组长度为2,默认为2

    //遍历
    for (int i = 1; i < nums.length; i++) {//i从1开始
        curDiff = nums[i] - nums[i - 1];//这里一定要从i开始,否则会越界

        if((preDiff >= 0 && curDiff < 0 ) || (preDiff <=0 && curDiff > 0)){//等于0是为了解决数组长度为2和中间平坡问题
            res++;//记录上下坡的值
            preDiff = curDiff;//这才更新数值,防止出现递增中间平坡问题

        }

    }

    return res;
}

53. 最大子序和⭐️

局部最优:

  1. 只要当前子序列和值为正数,那么就会对下一个元素起到正的反馈,这个子序列会越积越大,也就继续可以用这个序列
  2. 当前“连续和”为负数的时候立刻放弃**(将部分和置为0)**,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。
  • 题目链接:代码随想录

  • 解题思路:
    局部最优:只要当前子序列和值为正数,那么就会对下一个元素起到正的反馈,这个子序列会越积越大,也就继续可以用这个序列
    当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。
    结果集每次比较sum和count[i]谁更大,从而决定返回哪个

     * 
          贪心算法:一次遍历即出结果,大大降低时间复杂度
    
  • 图像理解:

    53.最大子序和

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值