題目來源:力扣
題目描述:
輸入一個整型數組,數組裏有正數也有負數。數組中的一個或連續多個整數組成一個子數組。求所有子數組的和的最大值。
要求時間複雜度爲O(n)。
=============================================
示例1:
輸入: nums = [-2,1,-3,4,-1,2,1,-5,4]
輸出: 6
解釋: 連續子數組 [4,-1,2,1] 的和最大,爲 6。
提示:
1 <= arr.length <= 10^5
-100 <= arr[i] <= 100
===============================================
審題:
該題要求時間複雜度爲O(n),對於連續子數組最大和問題,使用分治算法時間複雜度爲O(NlgN),而使用動態規劃算法時間複雜度爲O(N).因此本題考慮使用動態規劃算法求解.
接下來分析該問題的最優子結構,假設當前數組a[0:n]的連續子數組最大和爲, 它與數組a[0:n-1]的連續子數組最大和是否存在某種聯繫.進一步分析我們發現,由於數組a[0:n]的連續最大和子樹組可能出現在數組a[0:n]的中間位置,因此其與a[0:n-1]的連續最大和子樹組之間不存在直接的推導關係.由此可見我們從該角度出發無法推導出最優子結構.
上述思路無法進行下去的直接原因在於a[0:n]與a[0:n-1]兩個數組之間相差了一個a[n-1],而由於a[n-1]與a[0:n-1]的連續最大和子數組之間並不存在直接關聯,因此無法推導出最優子結構.
在使用動態規劃求解最優解問題中,通常涉及作出一個初始選擇, 在連續子數組最大和問題中,我們需要確定連續子數組的左右邊界.我們可以作出如下初始選擇:選擇i爲連續最大和子數組的右邊界,假設當前選擇爲最優選擇,我們使用表示以數組元素a[n]結尾的連續子樹組最大和.此時我們分析與的關係,我們可以推導出:
, ;
我們需要計算所有, 選擇最大值作爲連續子樹組的最大和.
注意到在計算時,我們需要計算 ,進一步我們爲了計算又涉及計算.而在計算時,我們又要再次計算,因此子問題存在重疊.故而應當使用動態規劃算法.
我們可以使用自底向上的動態規劃算法,依次計算.
java算法:
class Solution {
public int maxSubArray(int[] nums) {
int res = nums[nums.length-1];
for(int i = nums.length-2; i >=0 ; i--) {
nums[i] += Math.max(nums[i+1], 0);
res = Math.max(res, nums[i]);
}
return res;
}
}
時間複雜度分析:
從上述代碼結構不難發現,該算法的時間複雜度爲O(N).我們可是使用動態規劃算法的理論進行驗證.對於任意動態規劃算法,其時間複雜度爲一下兩項乘積:
- 算法涉及的子問題個數
- 在每一步解決子問題時,需要作出的選擇.
在上述算法中,子問題個數爲N, 我們需要計算S[1], S[2], …S[N].而在解決每一步解決子問題時,我們的選擇爲1, 例如在計算S[3]時,我們的連續最大和子數組右邊界是確定的,我們可以在O(1)的時間判斷其左邊界與S[2]保持一致還是變爲3.因此該算法的時間複雜度爲O(N).