假設一個問題比較複雜,暫時找不到全局最優解,那麼咱們能夠考慮把原問題拆成幾個小問題,分別求每一個小問題的最優解,再把這些「局部最優解」疊起來,就「看成」整個問題的最優解了。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;
}
複製代碼
平常生活中不少狀況,全局最優和局部最優有很大的區別,盲目追求全局最優有可能和預期結果截然不同。
看上去短的路可能岔路多,每次選則最短的路可能會繞一圈
看上去雪多的路可能路比較短,不如雪粘、路途長的路積累的雪球大
每次都是離乘客最近的車接單,那麼有些地方的乘客可能永遠打不到車
既然貪心算法不能保證全局最優,咱們爲何還要須要它呢?
好在前人的經驗總結了一些條件能夠參考:
常見場景有:揹包問題、分糖果、找零錢、區間覆蓋等
其實在前文中已經都提到了,這裏再總結一下。
證實一個場景能夠知足「局部最優極大程度趨近於全局最優」每每難於使用貪心求解。
通常來講若是一個問題能夠轉化爲擬陣,那就能夠貪心求解。但不是全部能夠貪心求解的問題都能轉化成擬陣。 擬陣的推導涉及一些數學知識,有興趣能夠看看。擬陣與最優問題