Day34~455.分发饼干、376. 摆动序列、53. 最大子序和

100 阅读3分钟

摘要

本文主要介绍了贪心算法的理论基础,以及LeetCode贪心算法的几个题目,包括455.分发饼干、376. 摆动序列、53. 最大子序和。

1、贪心算法理论基础

1.1 概念

什么是贪心

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

什么时候用贪心

说实话贪心算法并没有固定的套路。

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

贪心一般解题步骤

  • 将问题分解为若干个子问题
  • 找出适合的贪心策略
  • 求解每一个子问题的最优解
  • 将局部最优解堆叠成全局最优解

这个四步其实过于理论化了,我们平时在做贪心类的题目 很难去按照这四步去思考,真是有点“鸡肋”。

做题的时候,只要想清楚 局部最优 是什么,如果推导出全局最优,其实就够了。

2、455.分发饼干

2.1 思路

  • 局部最优:优先满足胃口大的孩子
  • 排序+双指针+贪心
  • 首先,对孩子的胃口和饼干的大小进行排序,从小到大
  • 接下来,我们采用贪心策略,尽量先满足胃口大的孩子
  • 我们从胃口最大的孩子开始,尝试匹配最大的饼干
  • 如果当前饼干满足了孩子的胃口,我们将数量+1,并尝试下一个孩子和饼干
  • 如果当前饼干不满足孩子的胃口,我们尝试下一个孩子,继续匹配当前饼干
  • 以此类推,直到所有孩子或所有饼干都被考虑完

2.2 代码

    public int findContentChildren(int[] g, int[] s) {
        int count = 0;
        Arrays.sort(g);
        Arrays.sort(s);
        
        int j = s.length-1;
        for(int i=g.length-1; i>=0; i--) {
            if(j >=0 && s[j] >= g[i]) {
                j--;
                count++;
            }
        }
        return count;
    }

3、376. 摆动序列

3.1 思路

  • 初始化摆动序列的长度 count 为1,因为序列中至少有一个元素。
  • 定义 preDiffcurDiff 分别表示前一个元素与当前元素之间的差值,以及当前元素与后一个元素之间的差值。
  • 如果 (preDiff >= 0 && curDiff < 0) || (preDiff <= 0 && curDiff > 0) 的条件成立,说明出现了摆动变化,摆动序列的长度就会增加1。
  • 在摆动变化发生时才更新 preDiff

这种贪心算法的核心思想是只关注摆动变化的情况,并且通过维护 preDiff 来判断是否出现了摆动。这样可以在一次遍历中找到最长的摆动序列长度。

3.2 代码

    public int wiggleMaxLength(int[] nums) {
        int count = 1;
        int preDiff = 0;
        int curDiff = 0;
        
        for(int i=0; i<nums.length-1; i++) {
            curDiff = nums[i+1] - nums[i];
            if((preDiff >= 0 && curDiff < 0) || (preDiff <= 0 && curDiff > 0)) {
                count++;
                preDiff = curDiff;
            }
        }
        return count;
    }

4、53. 最大子序和

4.1 思路

  • 初始化两个变量 maxSumcurrentSum,分别用于跟踪全局最大子数组和和当前子数组和。
  • 遍历整个数组,从第一个元素开始。
  • 对于每个元素,将其添加到当前子数组的末尾,并更新 currentSum 为当前子数组的和。
  • 在每一步中,比较 currentSummaxSum,并将 currentSum 更新为它们中的较大值。
  • 如果 currentSum 变成负数,说明当前子数组的和不再对后续元素的和产生积极影响,因此我们可以放弃当前子数组,将 currentSum 重置为0,重新开始构建新的子数组。
  • 继续遍历数组,重复步骤 3 到步骤 5,直到遍历完整个数组。
  • 最终,maxSum 中存储的值即为最大子数组和。

4.2 代码

    public int maxSubArray(int[] nums) {
        int maxSum = Integer.MIN_VALUE;
        int curSum = 0;
​
        for(int i=0; i<nums.length; i++) {
            curSum += nums[i];
            maxSum = Math.max(maxSum, curSum);
            
            if(curSum < 0) {
               curSum = 0;
            }
        }
        return maxSum;
    }

参考资料

代码随想录-455.分发饼干

代码随想录-376. 摆动序列

代码随想录-53. 最大子序和