说实话贪心算法并没有固定的套路。
所以唯一的难点就是如何通过局部最优,推出整体最优
有同学问了如何验证可不可以用贪心算法呢?
最好用的策略就是举反例,如果想不到反例,那么就试一试贪心吧。
一般数学证明有如下两种方法:
- 数学归纳法
- 反证法
面试中基本不会让面试者现场证明贪心的合理性,代码写出来跑过测试用例即可,或者自己能自圆其说理由就行了
贪心算法一般分为如下四步:
- 将问题分解为若干个子问题
- 找出适合的贪心策略
- 求解每一个子问题的最优解
- 将局部最优解堆叠成全局最优解
2.解题思路
- 为了满足更多的小孩,就不要造成饼干尺寸的浪费。
- 大尺寸的饼干既可以满足胃口大的孩子也可以满足胃口小的孩子,那么就应该优先满足胃口大的。
- 这里的局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。
首先对数组 gg 和 ss 排序,然后从小到大遍历 gg 中的每个元素,对于每个元素找到能满足该元素的 ss 中的最小的元素。具体而言,令 ii 是 gg 的下标,jj 是 ss 的下标,初始时 ii 和 jj 都为 00,进行如下操作。
对于每个元素 g[i]g[i],找到未被使用的最小的 jj 使得 g[i] \le s[j]g[i]≤s[j],则 s[j]s[j] 可以满足 g[i]g[i]。由于 gg 和 ss 已经排好序,因此整个过程只需要对数组 gg 和 ss 各遍历一次。当两个数组之一遍历结束时,说明所有的孩子都被分配到了饼干,或者所有的饼干都已经被分配或被尝试分配(可能有些饼干无法分配给任何孩子),此时被分配到饼干的孩子数量即为可以满足的最多数量。
import java.util.Arrays; //胃口值 g 饼干s public class AssignCookies { // 思路1:优先考虑饼干,小饼干先喂饱小胃口 public int findContentChildren(int[] g, int[] s) { Arrays.sort(g); Arrays.sort(s); int m = g.length; int n = s.length; int count = 0; for (int i = 0, j = 0; i < m && j < n; i++, j++){ while (j < n && g[i] > s[j]){ j++; }if(j < n){ count++; } }return count; } }
// 思路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;
public class WiggleSubsequence { public int wiggleMaxLength(int[] nums) { if(nums.length == 1){ return 1; } int res = 1; int cur = 0;//当前一对差值 int pre = 0;// 前一对差值 for(int i = 1; i < nums.length; i++){ cur = nums[i] - nums[i - 1]; // 出现峰值 if(cur > 0 && pre <=0 || cur < 0 && pre >=0){ res++; pre = cur; } } return res; } }
贪心贪的是哪里呢?
如果 -2 1 在一起,计算起点的时候,一定是从1开始计算,因为负数只会拉低总和,这就是贪心贪的地方!
局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。
全局最优:选取最大“连续和”
局部最优的情况下,并记录最大的“连续和”,可以推出全局最优。
从代码角度上来讲:遍历nums,从头开始用count累积,如果count一旦加上nums[i]变为负数,那么就应该从nums[i+1]开始从0累积count了,因为已经变为负数的count,只会拖累总和。
这相当于是暴力解法中的不断调整最大子序和区间的起始位置。
那有同学问了,区间终止位置不用调整么? 如何才能得到最大“连续和”呢?
区间的终止位置,其实就是如果count取到最大值了,及时记录下来了。例如如下代码:
if (count > result) result = count;
public class MaximumSubarray { public int maxSubArray(int[] nums) { int res = Integer.MIN_VALUE;//结果 int count = 0;//根据count值来更新结果 for(int i = 0; i < nums.length; i++){ count += nums[i];//count每次累加num[i]的值 //count比res小,更新结果 if(count > res){ res = count; //count小于0,则将count归零,并从i+1开始累加 }if(count < 0){ count = 0; } } return res; } }