力扣刷題系列 貪心思想I

2021-10-23 21:44:59 字數 3412 閱讀 1911

以下內容參考於: 與 僅作為個人日後複習查閱。

貪心演算法總是作出在當前看來最好的選擇,也就是說貪心演算法並不從整體最優考慮,它所作出的選擇只是在某種意義上的區域性最優選擇。

只有在滿足最優子結構的情況下貪心演算法得到的結果才是最優結果。

比如找錢的問題,我要給你一百,那麼我盡可能每一次給你最多的。

或者比如磁碟的最優儲存問題,所謂貪心選擇性質是指所求問題的整體最優解可以通過一系列區域性最優的選擇,即貪心選擇來達到。

prim和kruskal演算法都是每次選擇最小的邊納入生成樹。

從許多可以用貪心演算法求解的問題中看到這類問題一般具有兩個重要的性質:貪心選擇性質和最優子結構性質。

所謂貪心選擇性質是指所求問題的整體最優解可以通過一系列區域性最優的選擇,即貪心選擇來達到。這也是貪心問題和動態規劃問題的主要區別。

在n行m列的正整數矩陣中,要求從每一行中選乙個數,使得選出的n個數的和最大。

可運用貪心策略,選n次,每一次選相應行中的最大值即可。

但是,在乙個n*m的方格陣中,每一格仔賦予乙個數,規定每次移動時只能向上或向右,現試找出一條路徑,使其從左下角至右上角所經過的權值之和最大。

同樣考慮貪心策略,從左下角向右上角移動,每次移動選擇權值較大的乙個方向。

3  4   6

1 2 100

以2*3矩陣為例,採用貪心的策略得到的是1,3,4,6和為14但是實際的最優結果為1,2,100,6和為109.

所以說貪心演算法並不是總是可行,證明當前問題存在貪心選擇性質(全域性最優解可以通過區域性最優貪心選擇達到)和最優子結構性質(問題的最優解包含了其子問題的最優解)。所以貪心問題如果當前的選擇不會干擾之後的選擇,則不會出現問題。

其他的情況就需要進行證明,證明的最好辦法就是將最小子問題進行一步步的合併,直到最後還原為最後的原問題,若所得到的解是總體最優的則可以使用貪心思想,否則不可以。

比如上面的問題,我們的走一步的最優解為1,3,然後我們判斷一次走兩步的最優解是否任然為1,3這個路徑,答案顯然不是,變為 1,2,100這個路徑,所以顯然不能使用貪心思想。

用貪心法求解問題應該考慮如下幾個方面:

(1)候選集合c:為了構造問題的解決方案,有乙個候選集合c作為問題的可能解,即問題的最終解均取自於候選集合c。例如在找零錢問題中,各種面值的貨幣構成候選集合。

(2)解集合s:隨著貪心選擇的進行,解集合s不斷擴充套件,直到構成乙個滿足問題的完整解。例如在找零錢問題中,已付出的貨幣構成解集合。

3)可行解函式solution:檢查解集合s是否構成問題的乙個可行解。例如,在找零錢問題中,可行解函式是已付出的貨幣金額恰好等於應找零錢。

(4)選擇函式select:即貪心策略,這是貪心法的關鍵,它指出哪個候選物件最有希望構成問題的解,選擇函式通常和目標函式有關。例如,在找零錢問題中,貪心策略就是在候選集合中選擇面值最大的貨幣。

(5)約束函式constraint:檢查解集合中加入乙個候選物件是否滿足約束條件。例如,在找零錢問題中,約束函式是每一步選擇的貨幣和已付出的貨幣相加不超過應找零錢。

貪心演算法的一般框架:

greedy(c) //c是問題的輸入集合即候選集合

; //初始解集合為空集

while (not solution(s)) //集合s沒有構成問題的乙個可行解

;c=c-;

}return s;

}

從問題的某乙個初始解出發,通過一系列的貪心選擇——當前狀態下的區域性最優選擇,逐步逼近給定的目標,盡可能快地求得更好的解。

在貪心演算法(greedy method)中採用逐步構造最優解的方法。在每個階段,都作出乙個按某個評價函式最優的決策,該最優評價函式稱為貪心準則(greedy criterion)。

貪心演算法的正確性,就是要證明按貪心準則求得的解是全域性最優解。

①決定問題的最優子結構

②設計出乙個遞迴解

③證明在遞迴的任一階段,最優選擇之一總是貪心選擇。那麼,做貪心選擇總是安全的。

④證明通過做貪心選擇,所有子問題(除乙個以外)都為空。

⑤設計出乙個實現貪心策略的遞迴演算法。

⑥將遞迴演算法轉換成迭代演算法。

動態規劃演算法通常以自底向上的方式解各子問題,而貪心演算法則通常以自頂向下的方式進行,以迭代的方式作出相繼的貪心選擇,每作一次貪心選擇就將所求問題簡化為規模更小的子問題。

對於乙個具體問題,要確定它是否具有貪心選擇性質,必須證明每一步所作的貪心選擇最終導致問題的整體最優解。

當乙個問題的最優解包含其子問題的最優解時,稱此問題具有最優子結構性質。

問題的最優子結構性質是該問題可用動態規劃演算法或貪心演算法求解的關鍵特徵

貪心演算法和動態規劃演算法都要求問題具有最優子結構性質,這是2類演算法的乙個共同點。

假設1元、2元、5元、10元、20元、50元、100元的紙幣分別有c0, c1, c2, c3, c4, c5, c6張。現在要用這些錢來支付k元,至少要用多少張紙幣?用貪心演算法的思想,很顯然,每一步盡可能用面值大的紙幣即可。在日常生活中我們自然而然也是這麼做的。

public static void main(string args) ;

main main = new main();

int target = 800;

int ci = main.findmoney(target,coin);

system.out.println(ci);

}public int findmoney(int target,int cointype)

}return count;

}

有n個需要在同一天使用同乙個教室的活動a1,a2,…,an,教室同一時刻只能由乙個活動使用。每個活動ai都有乙個開始時間si和結束時間fi 。一旦被選擇後,活動ai就佔據半開時間區間[si,fi)。如果[si,fi]和[sj,fj]互不重疊,ai和aj兩個活動就可以被安排在這一天。該問題就是要安排這些活動使得盡量多的活動能不衝突的舉行。

public void testarrangeactivity() ;

int end = ;

listresults = arrangeactivity(start, end);

for (int i = 0; i < results.size(); i++)

}public listarrangeactivity(int s, int e)

}return results;

}

部分揹包問題, 有n個物體,第i個物體重量為wi,價值為vi,在總重量不超過c的情況下,讓總價值盡可能的高。每個物體都可以只取一部分。我們可以考慮重量和價值的比值作為單價。

力扣刷題系列

給定兩個大小為 m 和 n 的有序陣列 nums1 和 nums2。請你找出這兩個有序陣列的中位數,並且要求演算法的時間複雜度為 o log m n 你可以假設 nums1 和 nums2 不會同時為空。從中學知識知道,如果需要求一組數字的中位數,那麼先要從小到大排列這些數字。接著,如果總共有奇數個...

力扣刷題 陣列系列 2

刷題的順序,按照前輩的leetcode cookbook上的順序 給定乙個排序陣列,你需要在 原地 刪除重複出現的元素,使得每個元素只出現一次,返回移除後陣列的新長度。不要使用額外的陣列空間,你必須在 原地 修改輸入陣列 並在使用 o 1 額外空間的條件下完成 思考 1.題目要求原地刪除重複的元素,...

刷題 力扣 461 陣列拆分 I

題目鏈結 題目描述 給定長度為 2n 的整數陣列 nums 你的任務是將這些數分成 n 對,例如 a1,b1 a2,b2 an,bn 使得從 1 到 n 的 min ai,bi 總和最大。返回該 最大總和 示例 1 輸入 nums 1,4,3,2 輸出 4 解釋 所有可能的分法 忽略元素順序 為 1...