這是《劍指offer》系列的第一篇,這個系列的文章主要用於記錄看書時的一些感想,做個記錄。
題目
輸入一個整型數組,數組裏有正數也有負數。數組中一個或連續的多個整數組成一個子數組。求所有子數組的和的最大值。要求時間複雜度爲O(n)。例:
思路
這裏採用動態規劃的思想:
- 第一步:做一個選擇,基於這個選擇產生一個或多個待解的子問題
這裏用函數 表示以第 個數字結尾的子數組的最大和,其中 。注意到函數 的不同取值構成了原題可能解的全集。例:當 的時候,有 。
這裏我們選擇子數組的結束位置 ,並且假定這個選擇是最優解。即:我們假設結束於下標爲 的子數組的最大和是原數組中所有子數組的最大和。
選擇了結束位置之後,數組下標 6 的右邊不用再進行考慮。那麼基於 產生子問題 ,意義是結束於下標爲 的子數組的最大和。
- 第二步:證明問題具有最優子結構性質,並得到遞歸式
使用“剪切 - 粘貼”反證法,證明在 的條件下問題具有最優子結構性質:
假設 不是數組區間 內結束於下標爲 的子數組的最大和,那麼我們將 從 中剪切去掉,並把最優解 粘貼其中得到 , 則有 ,與“ 是最優解”矛盾,故原假設不成立,得證。
這裏稍微有點繞,如下圖:
這裏我們證明的是: 區間在 的時候一定會被 區間包含。
注:這裏約束 的意義在於,當子問題的解是負數的時候,即使它是子問題能達到的最大值,也會拖了原問題的後腿,還不如直接等於 。例如 的子問題 ,那結束於下標爲 的子數組的最大和應該等於 本身,即 。這是來自於我們定義這個函數時隱含的約束
由此我們證明了原問題的最優解 “ 結束於下標爲 的子數組的最大和 ” 包含了它的子問題 “ 結束於下標爲 的子數組的最大和 ” 的最優解。我們稱這個問題具有最優子結構。
得到以下遞推式:
- 第三步:證明問題具有重疊子問題性質
如果遞歸算法反覆求解相同的子問題,我們稱最優化問題具有重疊子問題性質,這裏我們採用子問題圖來可視化子問題之間的依賴關係,其中節點代表子問題,弧代表調用關係:
例如規模爲4的子問題在求解時會調用規模爲3、2和1的子問題,而處理規模爲3的子問題的時候又會調用規模爲2和1的子問題,造成高昂的計算代價。
- 第四步:使用動態規劃進行求解
動態規劃求解分爲帶備忘錄的自頂向下法和帶表格的自底向上法。
以下附上劍指offer提供的自底向上法:
結語
動態規劃的題目常見,做多了題,有時候稀裏糊塗地套上去試一下能做出來。但一直不懂背後的原理。這篇主要是用《算法導論》裏面的分析手法分析了下《劍指offer》裏的題,得到了些粗淺的看法,以後還要多加練習。
Reference:
《算法導論》p216
《劍指offer》p171