java如何求最大子数组的和 蛮力算法 动态规划算法

下面介绍五种方法求解最大子数组的和:其中包含蛮力算法,以及其优化;动态规划算法,以及其优化算法

package datastruct.usearray;

import java.util.Scanner;

/**
 * 
 * 如何求最大子数组的和
 */
public class GetSumOfSubArray {
	//方法一:蛮力算法 时间复杂度为:o(n^3)
	    private static void  getSumOfSubArray(int array[]) {
            int n=array.length;
            int thisSum,maxSum=Integer.MIN_VALUE,k,i,j;
	    	for ( i = 0; i < n; i++) {
				for ( j = i; j <n; j++) {
					  thisSum=0;
					System.out.print("子数组有:");  
					for ( k=i;k<=j;k++) {//k 为i,j分别为子数组的起始位置
						thisSum=thisSum+array[k];
						System.out.print(array[k]+" ");//可以输出所有的子数组是哪些
					}
					 System.out.println();
					if (thisSum>maxSum) {
						maxSum=thisSum;
					}
				}
			}
	    	System.out.println("方法一:最大子数组之和为:"+maxSum);
		}
	 
	   //方法二:重复利用已经计算的子数组和,相比较方法一,时间复杂度为:o(n^2)
	    private static void method2 (int array[]) {
	    	int n=array.length;
	    	int maxSum=Integer.MIN_VALUE;
	    	for (int i = 0; i < n; i++) {
	    		 int sum=0;
				 for (int j = i; j < n; j++) {
					 sum=sum+array[j];//相比较方法一:利用了已经计算的子数组和
					 if (sum>maxSum) {
						 maxSum=sum;
					}
				}
			}
	    	System.out.println("方法二:最大子数组之和为:"+maxSum);
		}
	    
	    /**
	     * 利用动态规划解题:该方法时间复杂度为:o(n),但是额外使用了两个数组空间,其空间复杂度为:o(n)
	     * 解题思路:对于一个数组,求最大子数组之和,我们可以分为三部分:
	     * 我们以最后一个元素array[n-1]为例子:
	     * 1:array[n-1]自己构成最大的子数组
	     * 2:包含array[n-1]的最大子数组,即以array[n-1]结尾,我们用End[n-1]表示
	     * 3:不包含array[n-1]的最大子数组,那么求array[0]...array[n-1]的子数组,可以转化为求
	     *    array[0]...array[n-2]的最大子数组
	     *    
	     * 由以上可知:All[n-1]=max{array[n-1],End[n-1],All[n-1]}
	     *          All[n-1]表示为:array[0]...array[n-1]的最大子数组之和
	     */
	    private static int max(int a,int b){
	    	return a>b?a:b;
	    }
	    private static void  method3(int array[]) {
	    	int n=array.length;
	    	int End[]=new int [n];
	    	int All[]=new int [n];
	    	//初始化:当数组中只有一个元素时
	    	End[0]=All[0]=array[0];
	    	End[n-1]=All[n-1]=array[n-1];
	    	
	    	for (int i = 1; i <n; i++) {
				End[i]=max(End[i-1]+array[i], array[i]);
				All[i]=max(End[i], All[i-1]);
			}
	    	System.out.println("方法三:最大子数组之和为:"+All[n-1]);
			
		}
	    /**
	     *  优化动态规划
	     *  为了进一步降低空间复杂度,我们可以定义两个变量用来保存方法三中的
	     *  End[i-1]和All[i-1]
	     *  
	     */
	    private static void method4(int array[]) {
		    int n=array.length;
		    int nEnd=array[0]; //n个元素的最大组数组之和
		    int nAll=array[0];//包含组后一个元素的子数组之和
		    for (int i = 1; i <n ; i++) {
				nEnd=max(nEnd+array[i], array[i]);
				nAll=max(nEnd, nAll);
			}
		    
		    System.out.println("方法四:最大子数组之和为:"+nAll);
		}
	  
	    /**
	     * 方法五:求出最大数组之和,并得到最大子数组
	     */
	    
	     private static int begin=0;//记录最大子数组的起始位置
	     private static int end=0;  //记录最小子数组的结束位置
	     
	     private static void method5(int array[]) {
	    	 int maxSum=Integer.MIN_VALUE; //子数组最大值
	    	 int nSum=0;//包含子数组最后一位的最大值
	    	 int nstart=0;
	    	 for (int i = 0; i < array.length; i++) {
				if (nSum<0) {
					nSum=array[i];
					nstart=array[i];
				}else {
					nSum+=array[i];
				}
				if (nSum>maxSum) {
					maxSum=nSum;
					begin=nstart;
					end=i;
				}
			}
	    	 System.out.println("方法五:最大子数组之和为:"+maxSum);
	    	 System.out.println("起始位置为:"+begin+"  结束位置为:"+end);
	    	 System.out.println("最大数组是:");
	    	 for (int i = begin; i <=end; i++) {
				System.out.print(array[i]+" ");
			}
	     }
	     
         public static void main(String[] args) {
        	 Scanner sc=new Scanner(System.in);
        	 System.out.println("输入数组元素个数:");
             int n=sc.nextInt();
             System.out.println("输入"+n+"个数组元素:");
             int [] arry=new int [n];
             for (int i = 0; i <n; i++) {
				 arry[i]=sc.nextInt();
			}
           // 调用方法一:  
              getSumOfSubArray(arry);
           // 调用方法二:
              method2(arry);
           // 调用方法三: 
              method3(arry);
           // 调用方法四:
               method4(arry);
           // 调用方法五:
               method5(arry);
		}
	      
}


结果如下:

              

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值