Given an integer array nums
, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example:
Input: [-2,1,-3,4,-1,2,1,-5,4], Output: 6 Explanation: [4,-1,2,1] has the largest sum = 6.
两种方法,一种是O(n)完事,另一种在算法导论看过,就是二分法。
第一种方法
比较每一个数字与累加的sum比较,当前数字比sum大就从当前数字重新累加,当然还用一个max存储最大的子数组和。
public int maxSubArray(int[] nums) { if (nums == null) { return 0; } if (nums.length == 1){ return nums[0]; } int max = nums[nums.length-1]; for (int i = nums.length-2; i >= 0; i--) { nums[i] = Math.max(nums[i],nums[i]+nums[i+1]); max = Math.max(nums[i],max); } return max; }
第二种方法
Divide and conquer 方法:
对于任何一个array来说,有三种可能:
1。它的maximum subarray 落在它的左边;
2。maximum subarray 落在它的右边;
3。maximum subarray 落在它的中间。
对于第一,二种情况,利用二分法就很容易得到,base case 是如果只有一个数字了,那么就返回。
对于第三种情况,如果落在中间,那么我们要从左右两边返回的两个 mss 中,挑出一个大的,再从 (左右中大的值) 和 (左+右)中挑出一个大的。具体看下面代码。
public class Solution { public int maxSubArray(int[] nums) { // Solution 3: Divide and Conquer. O(nlogn) if(nums == null || nums.length == 0) return 0; return Max_Subarray_Sum(nums, 0, nums.length-1); } public int Max_Subarray_Sum(int[] nums, int left, int right) { if(left == right) // base case: meaning there is only one element. return nums[left]; int middle = (left + right) / 2; // calculate the middle one. // recursively call Max_Subarray_Sum to go down to base case. int left_mss = Max_Subarray_Sum(nums, left, middle); int right_mss = Max_Subarray_Sum(nums, middle+1, right); // set up leftSum, rightSum and sum. int leftSum = Integer.MIN_VALUE; int rightSum = Integer.MIN_VALUE; int sum = 0; // calculate the maximum subarray sum for right half part. for(int i=middle+1; i<= right; i++) { sum += nums[i]; rightSum = Integer.max(rightSum, sum); } sum = 0; // reset the sum to 0. // calculate the maximum subarray sum for left half part. for(int i=middle; i>= left; i--) { sum += nums[i]; leftSum = Integer.max(leftSum, sum); } // choose the max between left and right from down level. int res = Integer.max(left_mss, right_mss); // choose the max between res and middle range. return Integer.max(res, leftSum + rightSum); } }