首页 > 代码库 > 最大子数组问题(求连续子数组的最大和)

最大子数组问题(求连续子数组的最大和)

在<算法导论>第四章分治策略(Divider and Conquer)4.1节提出了最大子数组问题。其转化就是求数组a={1, -2, 3, 10, -4, 7 , 2, -5}中连续子数组的最大和。

对于这个问题,很容想到一种暴力求解的方法:简单地尝试对所有可能的的组合进行求和。对数组为n存在n*(n-1)/2中组合,然后对每个组合进行求和。即三个for循环遍历,求出数组中每一个子数组的和,最终求出这些子数组的最大的一个值。记Sum[i,...,j]为数组a中第i个元素到第j个元素的和(其中0<=i<=j<n),遍历所有可能的Sum[i,...,j],那么时间复杂度(最大运行时间running Time)为Ο(n^3)。

 1 package algorithms; 2  3 /** 4  * @author public 5  *本段代码参考编程之美 6  */ 7 public class MaxSubarraySum { 8      9     static int[] a = {1, -2, 3, 10, -4, 7, 2, -5};10     static int sum;11     static int maxSum = 0;12     public static void main(String[] args) {13         // TODO Auto-generated method stub14         for (int i = 0; i < a.length; i++) {15             for (int j = i; j < a.length; j++) {16                 for (int k = i; k <= j; k++) {17                     sum += a[k];18                 }19                 if (sum > maxSum) {20                     maxSum = sum;                    21                 }22                 sum = 0;//无论是sum>maxSum还是sum<=maxSum都要对sum进行清零操作23             }24         }25         26         System.out.println("maxSum="+maxSum);27         28     }29 30 }

运行结果:

maxSum=18

在算法导论4.1-5习题提到如下思想:最大字数组问题设计一个非递归的、线性时间的算法。从数组的左边界开始,由左到右处理,记录到目前为止已经处理过的最大字数组。若已知a[1,...,j]的最大子数组,基于如下性质将解扩展为a[1,...,j+1]的最大子数组:a[1,...,j+1]的最大子数组要么是a[1,...,j]的最大子数组,要么是某个子数组a[i,...,j+1](1≤i≤j+1)。在已知a[1,...,j]的最大子数组的情况下,可以在线性时间内找出形如a[i,...,j+1]的最大子数组

实现方法:

 1 package algorithms; 2  3 public class FindMaxSubarray { 4      5     static int[] array = {1, -2, 3, 10, -4, 7, 2, -5}; 6  7     public static void main(String[] args) { 8         MaxSum(array); 9     }10 11     private static void MaxSum(int[] arraytmp) {12         // TODO Auto-generated method stub13         if (arraytmp==null) {14             return;15         }16         17         int curSum = 0, maxSum = 0;18         19         int indexStart = 0, indexEnd = 0;    //初始化字数组最大和下标20         21         for (int j = 0; j < arraytmp.length; j++) {22             curSum += arraytmp[j];//累加23             24             if (curSum < 0) {  //当前和小于0,重置为025                 curSum = 0;26                 indexStart = j+1;//调整字数组最大和的开始下标27             }28             29             if (curSum > maxSum) {    //当前和大于最大和,则重置最大和30                 maxSum = curSum;31                 indexEnd = j;    //调整字数组最大和的结束下标32             }33             34         }35         36         if (maxSum == 0) {        //最大和依然为0,说明数组中所有元素都为负值37             maxSum = arraytmp[0];38             indexStart = indexEnd = 0;        //初始化子数组最大和下标39             for (int j = 0; j < arraytmp.length; j++) {40                 if (arraytmp[j] > maxSum) {41                     maxSum =arraytmp[j];42                     indexEnd = indexStart = j;//调整子数组最大和下标43                 }44             }45         }46         47         for (int i = indexStart; i <= indexEnd; i++) {48             System.out.print(arraytmp[i]+" ");//输出最大和的子数组49         }50         System.out.println();51         System.out.println("maxSum="+maxSum);//输出子数组最大和52     }53 54 }

运行结果:

3 10 -4 7 2 maxSum=18

 

最大子数组问题(求连续子数组的最大和)