代码随想录算法训练营day31 || 455.分发饼干,376. 摆动序列,53.最大子序列的和

视频讲解:

贪心算法,你想先喂哪个小孩?| LeetCode:455.分发饼干_哔哩哔哩_bilibili

贪心算法,寻找摆动有细节!| LeetCode:376.摆动序列_哔哩哔哩_bilibili

贪心算法的巧妙需要慢慢体会!LeetCode:53. 最大子序和_哔哩哔哩_bilibili

455.分发饼干

思路:题目中明确饼干不可以分割,而要想贪心的策略,在于每一次都可以将最小分量的饼干分给最接近其胃口的孩子。

// 时间复杂度在于排序以及遍历两部分O(mlogm+nlogn)与O(m)或O(n)比较,显然时间复杂度为O(mlogm+nlogn)
// 空间复杂度O(1)

class Solution {
    public int findContentChildren(int[] g, int[] s) {
        // 题目的关键在于饼干不可以分割
        // 其次贪心的策略在于每一次都可以将最小分量的饼干分给最接近其胃口的孩子
        Arrays.sort(g);
        Arrays.sort(s);

        int j = 0;
        int count = 0;
        for(int i=0; i<g.length; i++){
            if(j == s.length)
                break;
            if(g[i]<=s[j]){
                count++;
                j++;
            }
            else if(g[i]>s[j]){
                //当前最小的胃口都比当前饼干来的大,说明饼干需要增大了
                i--;
                j++;
            }  
        }

        return count;
    }
}

376. 摆动序列

思路:贪心的策略就是将每一条子序列都变成忽增忽降的曲线,剔除上面存在的多个同一方向的节点。

// 时间复杂度O(n)
// 空间复杂度O(1)

class Solution {
    public int wiggleMaxLength(int[] nums) {

        if(nums.length == 1)
            return 1;
        
    //     // 记录最大摆动序列元素的个数
    //     int res = 1;
    //     // 拟定生成一个虚拟的平坡
    //     int prediff = 0;
    //     int curdiff = 0;
    //    for(int i=0; i<nums.length-1; i++){
    //        curdiff = nums[i+1] - nums[i];
    //        if((curdiff<0 && prediff>=0) || (curdiff>0 && prediff<=0)){
    //            res++;
    //            prediff = curdiff;   // 出现一个可行的坡度
    //        }
    //    }
    //     return res;

    // 解法二,通过提出同一递增或递减方向上的其他节点完成最长摆动序列的计数
    // 实际上就是统计出现拐点的个数,但是需要主要的是要讲初始的0位置直接算为一个拐点,其次针对长度为2时的数组,需要加入尾元素与首元素相等的判断,此操作蕴含在direction==-1的判断中
        int res = 1;
        int dierction = -1;

        for(int i=1; i<nums.length; i++){
            int minus = nums[i]-nums[i-1];
            
            // 开始初步遍历以及长度为2的数组的特殊操作 
            if(dierction == -1){
                if(minus<0) {
                    dierction = 0;
                    res++;
                }
                else if(minus>0) {
                    dierction = 1;
                    res++;
                }
            }
            if(minus<0 && dierction == 1){
                res++;
                dierction = 0;
            }
            if(minus>0 && dierction == 0){
                res++;
                dierction = 1;
            } 
        }

        return res;
    }
}

53.最大子序列的和

思路:贪心的策略在于需要每一步都保证当前的序列和是增加的,因此需要比较的目标包括sum与sum+nums[i]比较,以及sum+nums[i]与nums[i]比较,后者是防止sum是负数,而nums[i]是一个不足以使其取正的正数。其次特殊的情况在于sum与nums[i]都为负数,次数需要判断nums[i]与sum的大小,来保证取得nums[i]后序列和是增加的。

// 时间复杂度O(n)
// 空间复杂度O(1)

class Solution {
    public int maxSubArray(int[] nums) {
        // 贪心的思想就是每一步都需要使我的数组和变大一点
        // 仅仅比较sum+nums[i]和nums[i]的原因是不管nums[i]是正是负,不断加入元素总是存在序列和增加的可能,也许当前是负数但后续全是正数.并且题目中明确序列和是需要连续的,所以核心需要判断的就是当前元素加入上总和是不是比自身更低,那么证明之前的元素的求和失去了意义,只需选择当前元素更大的数值开始往后累加从而求取更大的序列和

        if(nums.length == 1)
            return nums[0];

        int max = nums[0];
        int sum = nums[0];
        int i=1;
        while(i<nums.length){
            // 特殊情况出现一段连续的负数,此时直接跳过
            if(sum<0 && nums[i]<0){
                if(sum < nums[i])
                    sum = nums[i];
            }
            else
                sum = Math.max(sum+nums[i], nums[i]);      
            i++;        
            max = sum>max? sum:max;
        }

        return max;
    }
}

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值