【问题描述】最大子序列和问题:给定整数A1, A2, ..., An(可能有负数),ΣAk的最大值(为方便起见,如果所有整数均为负数,则最大子序列和为0)。
通过四种方式来完成算法的实现,时间复杂度分别为:O(N*N*N)、O(N*N)、O(N*log N)、O(N)
【源码1】
package cn.edu.nwsuaf.cie.qhs.maxsubsum; /** * 求最大子序列和(1) * @author 静寞小森(沧海森林) * 下面的这种做法来求和,应该是程序员最直观想到的,时间复杂度为:O(N*N*N) * */ public class MaxSubSum1 { public static int maxSum(int[] array){ int maxSum = 0; for(int i = 0 ; i < array.length ; i++){ for(int j = i ; j < array.length;j++){ int curSum = 0; for (int k = i; k <= j; k++){ curSum += array[k]; if(curSum > maxSum){ maxSum = curSum; } } } } return maxSum; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[] array = new int[]{4,-3,5,-2,-1,2,6,-2}; long startTime = System.nanoTime(); System.out.println("最大子序列和为:"+MaxSubSum1.maxSum(array)); long endTime = System.nanoTime(); System.out.println("程序耗时为:"+(endTime-startTime)+" ns"); } }【源码2】
package cn.edu.nwsuaf.cie.qhs.maxsubsum; /** * 求最大子序列和(2) * * @author 静寞小森(沧海森林) * 第二种做法,是对做法(1)进行一下分析,可以得知,程序中第三层循环不是必须的,因为这个过程可以包含在第二层循环中,所以可以考虑去掉。 * 去掉一个for循环,可以得到循环的次数减少了n的倍数,所以时间复杂度为O(N*N) * */ public class MaxSubSum2 { public static int maxSum(int[] array) { int maxSum = 0; for (int i = 0; i < array.length; i++) { int curSum = 0;//这个变量的声明和初始化要提到第二层for的外面 for (int j = i; j < array.length; j++) { //在这里,就已经包括了(1)中的k的那个循环 curSum += array[j]; if (curSum > maxSum) { maxSum = curSum; } } } return maxSum; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[] array = new int[]{4,-3,5,-2,-1,2,6,-2}; long startTime = System.nanoTime(); System.out.println("最大子序列和为:"+MaxSubSum2.maxSum(array)); long endTime = System.nanoTime(); System.out.println("程序耗时为:"+(endTime-startTime)+" ns"); } }
package cn.edu.nwsuaf.cie.qhs.maxsubsum; /** * 求最大子序列和(3) * * @author 静寞小森(沧海森林) * 第三种方法,我们将采用“分而治之”的想法,进行编码。因为本程序,最大子序列和只能出现在三个位置上: * 左半部分、右半部分、跨着左右两半部分;所以我们可以采用二分的“分而治之”来进行分开解决问题。可知其时间复杂度为:O(N*log N) */ public class MaxSubSum3 { private static int max3(int a,int b,int c){ int temp = Math.max(a, b); return Math.max(temp, c); } private static int maxSumRec(int[] array,int left,int right){ if (left == right) return array[left] > 0 ? array[left] : 0; //二分 int center = (left+right)>>1;//右移位一次,为除法的除以2,但是效率比较高 int maxLeftSum = maxSumRec(array,left,center); int maxRightSum = maxSumRec(array,center+1,right); int maxLeftBorderSum = 0, curLeftBorderSum = 0; for(int i = center;i >= left; i--){ curLeftBorderSum += array[i] ; if(curLeftBorderSum > maxLeftBorderSum) maxLeftBorderSum = curLeftBorderSum; } int maxRightBorderSum = 0, curRightBorderSum = 0; for(int i = center+1; i <= right;i++){ curRightBorderSum += array[i]; if(curRightBorderSum > maxRightBorderSum) maxRightBorderSum = curRightBorderSum; } return max3(maxLeftSum,maxRightSum,maxRightBorderSum+maxLeftBorderSum); } public static int maxSum(int[] array){ return maxSumRec(array,0,array.length-1); } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[] array = new int[]{4,-3,5,-2,-1,2,6,-2}; long startTime = System.nanoTime(); System.out.println("最大子序列和为:"+MaxSubSum3.maxSum(array)); long endTime = System.nanoTime(); System.out.println("程序耗时为:"+(endTime-startTime)+" ns"); } }【源码4】
package cn.edu.nwsuaf.cie.qhs.maxsubsum; /** * 求最大子序列和(4) * * @author 静寞小森(沧海森林) * 第四种方法,是通过一个“联机算法”进行的最优算法计算,时间复杂度仅为O(N) * */ public class MaxSubSum4 { public static int maxSum(int[] array){ int maxSum = 0, curSum = 0; for (int i = 0; i < array.length; i++){ curSum += array[i]; if(curSum > maxSum){ maxSum = curSum; }else if(curSum < 0){ curSum = 0; } } return maxSum; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int[] array = new int[]{4,-3,5,-2,-1,2,6,-2}; long startTime = System.nanoTime(); System.out.println("最大子序列和为:"+MaxSubSum3.maxSum(array)); long endTime = System.nanoTime(); System.out.println("程序耗时为:"+(endTime-startTime)+" ns"); } }