题目: 给定一个数组 A[0,1..... ,n-1],求A的连续子数组,使得该子数组的和最大。
例如:
数组: 1,-2,3,10,-4,7,2,-5
最大子数组: 3,10,-4,7,2
解法1:(暴力code)
1 public class MaxSubArray { 2 3 public static int MaxArray(int [] arr,int n) 4 { 5 int maxSum = arr[0]; 6 int currSum; 7 for(int i = 0;i<n;i++) 8 { 9 10 for(int j = i ;j<n ;j++) 11 { 12 currSum = 0; 13 for(int k = i;k<j;k++) 14 { 15 currSum+=arr[k]; 16 } 17 if(currSum>maxSum) 18 { 19 maxSum = currSum; 20 } 21 22 } 23 } 24 25 return maxSum; 26 } 27 public static void main(String[] args) { 28 29 int [] array = {1,-2,3,10,-4,7,2,-5}; 30 int maxArray = MaxArray(array, array.length); 31 System.out.println(maxArray); 32 } 33 34 }
解法2.分治法
将数组从中间分开,那么最大子数组要么完全在左半边数组,要么完全在右半边数组,要么跨立在分界点上。
完全在左数组、右数组递归解决。
跨立在分界点上:实际上是左数组的最大后缀和右数组的最大前缀的和。因此,从分界点向前扫,向后扫即可
1 //解法2.分治法求解 2 public static int MaxAddSub(int [] arr,int from ,int to) 3 { 4 //定义递归的出口 5 if(to == from ) 6 return arr[from]; 7 //求数组的中间位置 8 int middle = (from + to)/2; 9 //左边最大的子数组的和 10 int m1 = MaxAddSub(arr, from, middle); 11 //右边最大子数组的和 12 int m2 = MaxAddSub(arr,middle+1,to); 13 14 //这种情况 就是最大的子序列在中间的情况 15 int i ,left = arr[middle],now = arr[middle]; 16 for(i = middle -1;i>=from;--i) 17 { 18 now += arr[i]; 19 //left中只保留向左 去的最大的自序列的情况 20 left = Math.max(now,left); 21 } 22 23 24 //向右的情况是从middle+1 开始的防止重复计算中间值的情况 25 int right = arr[middle+1]; 26 now = arr[middle+1]; 27 for( i = middle+2;i<= to;++i) 28 { 29 now += arr[i]; 30 // right只保留向右最大的情况 31 right = Math.max(now,right); 32 } 33 //m3 是向左最大的情况加上向右的最大情况 34 int m3 = left+right; 35 36 //最中返回这个区间中三中情况中值最大的情况 37 return Math.max(Math.max(m1,m2),m3); 38 39 }