假设一个问题比较复杂,暂时找不到全局最优解,那么咱们能够考虑把原问题拆成几个小问题,分别求每一个小问题的最优解,再把这些“局部最优解”叠起来,就“看成”整个问题的最优解了。java
在每一步中,选择当前最优而不是全局最优,这就是贪心。算法
贪心和分治都是将问题进行拆分来下降求解的复杂度,不一样的是,分治保证每一个任务相对独立,不考虑最不最优问题; 而贪心子任务间每每存在关联关系,每次取舍之间都选择当前最优。markdown
如何知道一个问题是否能够用贪心算法解决呢,分析问题和用贪心解决问题均可以参考一下步骤:cookie
每一个孩子最多只能给一块饼干,对每一个孩子 i,都有一个胃口值 g[i],这是能让孩子们知足胃口的饼干的最小尺寸;而且每块饼干 j,都有一个尺寸 s[j] 。若是 s[j] >= g[i],咱们能够将这个饼干 j 分配给孩子 i ,这个孩子会获得知足。你的目标是尽量知足越多数量的孩子,并输出这个最大数值。leetcode传送门oop
显而易见,知足最多数量的孩子spa
对于每一个孩子,应该选择能够知足这个孩子的胃口且尺寸最小的饼干code
从贪心的角度考虑,应该按照孩子的胃口从小到大的顺序依次知足每一个孩子orm
假设有 m 个孩子,胃口值分别是 g1 到 gm,有 n 块饼干,尺寸分别是 s1 到 sn 咱们将两个数列由小到大排序,知足gi <= gi+1 和 sj <= sj+1排序
能够知足第 i 个孩子的胃口的最小的饼干是第 j 块饼干,即 sj是剩下的饼干中知足 sj >= gi的最小值, 最优解是将第 j 块饼干分配给第 i 个孩子leetcode
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int numOfChildren = g.length, numOfCookies = s.length;
int count = 0;
for (int i = 0, j = 0; i < numOfChildren && j < numOfCookies; i++, j++) {
while (j < numOfCookies && g[i] > s[j]) {
j++;
}
if (j < numOfCookies) {
count++;
}
}
return count;
}
复制代码
平常生活中不少状况,全局最优和局部最优有很大的区别,盲目追求全局最优有可能和预期结果截然不同。
看上去短的路可能岔路多,每次选则最短的路可能会绕一圈
看上去雪多的路可能路比较短,不如雪粘、路途长的路积累的雪球大
每次都是离乘客最近的车接单,那么有些地方的乘客可能永远打不到车
既然贪心算法不能保证全局最优,咱们为何还要须要它呢?
好在前人的经验总结了一些条件能够参考:
常见场景有:背包问题、分糖果、找零钱、区间覆盖等
其实在前文中已经都提到了,这里再总结一下。
证实一个场景能够知足“局部最优极大程度趋近于全局最优”每每难于使用贪心求解。
通常来讲若是一个问题能够转化为拟阵,那就能够贪心求解。但不是全部能够贪心求解的问题都能转化成拟阵。 拟阵的推导涉及一些数学知识,有兴趣能够看看。拟阵与最优问题