在《演算法導論》中舉了買股票和割鐵棒的例子來說明動態規劃和貪心演算法的主體思想。
貪心演算法:總是做出在當前看來最好的情況。(不是整體最優的)
1. 問題及答案
先丟擲一個問題,類似於《演算法導論》中的股票問題。
1.1 問題
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
簡單的一句話概括,就是找一個陣列中擁有最大和的子陣列,返回其和。
答案(不唯一)只有6行,可以說是非常簡潔,且便於理解了。
1.2 一種答案
/*
*@lucastan
*/
int maxSubArray(vector<int> &nums) {
int ans = nums[0], i, sum = 0;
for(i = 0; i < nums.size(); i++){
sum += nums[i];
ans = max(sum, ans);
sum = max(sum, 0);
}
return ans;
}複製程式碼
2. 解題思路
讀完問題,我們立刻就能想到的是從頭開始加,總能列舉出來一個。
這個想法可以說是非常樸實了,但是……我們還是繼續思考吧,第二反應就是貪心演算法了(如果你能想到動態規劃的思想,也不錯啊,可以類似的求解)。
首先我們要說,貪心演算法的簡單定義是什麼?(答案是白色字型)
總是找到一個在當前看來最優的解。
然後,我們現在要求的是什麼?
陣列中擁有最大和的子陣列。
這樣一來,目標就明確了,我們肯定是需要遍歷陣列的,不然怎麼能確定我們考慮到了陣列中所有元素呢?
明確了目標,我們結合貪心演算法的定義,提出下一個問題,我們怎麼確定現在的子陣列元素的和到目前為止是最大的呢?
與在新增了下一個元素之前的陣列進行比較。
那萬一我們加到陣列的某一個位置的時候,出現了和為負的情況……
笨啊,一旦加到某個元素出現和為負的情況,我們就應該捨棄前面的所有元素,然後在下一個元素處重新開始求和。如果等於零,那麼我們就要從這個元素開始重新求和。
另外,不要鑽最大子陣列在中間的這一種情況的牛角尖,除非在計算時陣列前面的元素和小於等於零,否則我們在這個程式碼裡,永遠會得到[0...x](x代表子陣列的最後一個元素序號,[0...x]難道不是他的子陣列嗎?就算我們最後得到陣列本身,他也是該陣列的子陣列)。
3. 一點想法
文章看到這裡,可能就有人發現了,這個問題並不是真的應用了貪心演算法,我們只是借來了貪心演算法一點點的思想,然後就得到了問題的解答。
(完整的貪心演算法思想在這裡是不能應用的,如果題目不要求子陣列連續,那麼倒是可以完整的應用貪心演算法思想,但這樣一來問題也就失去了意義。)
看了標題和開頭的一點點胡言亂語,你是不是真的以為我要講貪心演算法了,哼,天真。