題目連接: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;
法二(借鑑):時間複雜度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;
法三(借鑑):分治,時間複雜度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 }