53.Maximum Subarray

題目連接:https://leetcode.com/problems/maximum-subarray/description/數組

題目大意:給出一串數組,找出其最大連續子序列和,例子以下:ide

法一(超時):時間複雜度o(n^2),兩層for循環,記錄每個數值後的連續序列的最大和,裏層for循環記錄當前數值的連續序列的最大和,若是比最大值大,則記錄。spa

這個方法能夠用來解決記錄最大序列和的開始和結束下標的問題,即在裏層for循環中的當前數值的連續序列的最大和比最大值大時,出現調換時能夠在這個步驟中記錄開始和結束下標。.net

代碼以下:code

 1 int res = Integer.MIN_VALUE;
 2         for(int i = 0; i < nums.length; i++) {
 3             int cnt = 0;
 4             //對於每個數值,判斷其後面的連續子序列和獲得最大值
 5             for(int j = i; j < nums.length; j++) {
 6                 cnt += nums[j];
 7                 if(cnt > res) {
 8                     res = cnt;
 9                 }
10             }
11         }
12         return res;
View Code

法二(借鑑):時間複雜度o(n),代碼以下(耗時13ms):blog

 1         //法一
 2 /*        
 3         //這裏要把res賦值爲最小值,以防序列中負數的出現
 4         int res = Integer.MIN_VALUE;
 5         int sum = 0;
 6         for(int i = 0; i < nums.length; i++) {
 7             if(sum < 0) {
 8                 sum = nums[i];//若是當前值前面的sum<0,則將sum從新賦值爲當前值,以此值爲新的起點開始計算最大和
 9             }
10             else {
11                 sum += nums[i];//不然, 將當前值加入sum中
12             }
13             if(sum > res) {
14                 res = sum;
15             }
16         }
17         return res;*/
18         //法二
19         //結論:若是a[i]是負的,那麼它不可能表明最優序列的起點,由於任何包含a[i]的做爲起點的子序列均可以經過a[i+1]做起點而獲得改進。相似地,任何負的子序列不多是最優子序列的前綴
20         //若是在內循環中檢測到從a[i]到a[j]的子序列是負的,那麼能夠推動i到j+1。
21         //在這裏的運用也就是當sum<0時,即刻將sum重置爲0。
22         //這裏必定要把res賦值爲最小值,由於序列中會有負數的狀況
23         int res = Integer.MIN_VALUE;
24         int sum = 0;
25         for(int i = 0; i < nums.length; i++) {
26             sum += nums[i];//System.out.println(sum);
27             if(sum > res) {
28                 res = sum;
29             }
30             //這裏不要用else,由於相似序列{-2,-1}這種就計算不到最後的解
31             if(sum < 0) {//若是sum<0,則將sum重置,也就是發現sum<0,則說明此序列不會是最大和序列
32                 sum = 0;
33             }
34         }
35         return res;
View Code

法三(借鑑):分治,時間複雜度o(nlogn),參考http://blog.csdn.net/silangquan/article/details/8062229, 代碼以下(耗時18ms):遞歸

 1     public int maxSubArray(int[] nums) {
 2         return solution(nums, 0, nums.length - 1);
 3     }
 4     
 5     public int solution(int[] a, int left, int right) {
 6         //處理left==right中間值狀況
 7         if(left == right) {
 8             return a[left];
 9         }
10         
11         int mid = (left + right) / 2;
12         //遞歸求左邊最大和
13         int maxLeft = solution(a, left, mid);
14         //遞歸求右邊最大和
15         int maxRight = solution(a, mid + 1, right);
16         
17         //當前數組左邊包含最後一個數的最大和
18         int maxLeftSum = Integer.MIN_VALUE;
19         int leftSum = 0;
20         for(int i = mid; i >= left; i--) {
21             leftSum += a[i];
22             if(maxLeftSum < leftSum) {
23                 maxLeftSum = leftSum;
24             }
25         }
26         
27         //當前數組右邊包含第一個數的最大和
28         int maxRightSum = Integer.MIN_VALUE;
29         int rightSum = 0;
30         for(int i = mid + 1; i <= right; i++) {
31             rightSum += a[i];
32             if(maxRightSum < rightSum) {
33                 maxRightSum = rightSum;
34             }
35         }
36         
37         //左邊最大和,右邊最大和,包含左右兩邊的最大和,返回這三個值中的最大值
38         int tmp = maxLeft > maxRight ? maxLeft : maxRight;
39         return tmp > (maxLeftSum + maxRightSum) ? tmp : (maxLeftSum + maxRightSum);
40     }
View Code
相關文章
相關標籤/搜索