Leetcode題解之動態規劃(3)最大子序和
阿新 • • 發佈:2018-12-02
題目描述:
最大子序和
給定一個整數陣列 nums
,找到一個具有最大和的連續子陣列(子陣列最少包含一個元素),返回其最大和。
示例:
輸入: [-2,1,-3,4,-1,2,1,-5,4], 輸出: 6 解釋: 連續子陣列 [4,-1,2,1] 的和最大,為 6。
進階:
如果你已經實現複雜度為 O(n
思路: 第一種 暴力破解。O(N^2)沒啥好說的
第二種 掃描法O(N) :
當我們加上一個正數時,和會增加;當我們加上一個負數時,和會減少。如果當前得到的和是個負數,那麼這個和在接下來的累加中應該拋棄並重新清零,不然的話這個負數將會減少接下來的和。
第三種:動態規劃:
設sum[i]為以第i個元素結尾且和最大的連續子陣列。假設對於元素i,所有以它前面的元素結尾的子陣列的長度都已經求得,那麼以第i個元素結尾且和最大的連續子陣列實際上,要麼是以第i-1個元素結尾且和最大的連續子陣列加上這個元素,要麼是隻包含第i個元素,即sum[i]
= max(sum[i-1] + a[i], a[i])。可以通過判斷sum[i-1] + a[i]是否大於a[i]來做選擇,而這實際上等價於判斷sum[i-1]是否大於0。由於每次運算只需要前一次的結果,因此並不需要像普通的動態規劃那樣保留之前所有的計算結果,只需要保留上一次的即可,因此演算法的時間和空間複雜度都很小
//暴力列舉: private int max = Integer.MIN_VALUE; public int maxSubArray(int[] nums) { int sum; for (int i = 0; i < nums.length; i++) {// 子序列左端點 sum = 0; for (int j = i; j < nums.length; j++) {// 子序列右端點 sum += nums[j];// 這裡就相當於每次根據前一次的序列來計算新的序列 if (sum > max) max = sum; } } return max; } //掃描法: class Solution { public int maxSubArray(int[] nums) { int current=nums[0]; int sum=nums[0]; //我們考慮如果全是負數,那麼返回最大的負數,如果最後的和為正,那麼就使用掃描法 for(int i=1;i<nums.length;i++) { if(current<0)current=nums[i];//當前數小於0 肯定會捨去(否則將會影響接下來的和),換為下一個數 else current+=nums[i];//如果當前數不小於0,那麼他會對接下來的和有積極影響 if(current>sum)sum=current;//這裡既實現了負數返回最大也實現了掃描法 //這裡其實已經隱式的列舉了所有可能,保留了所有可能的最大值 } return sum; } } //動態規劃 class Solution { public int maxSubArray(int[] nums) {// 動態規劃法 int sum=nums[0]; int n=nums[0]; for(int i=1;i<nums.length;i++) { if(n>0)n+=nums[i]; else n=nums[i]; if(sum<n)sum=n; } return sum; } }