最大子数组的和并确定子数组的位置 数对之差的最大值

求最大子数组之和

蛮力法:

算法思路:找出所有子数组,然后求出子数组的和然后,在所有子数组的和中取最大值

时间复杂度:O(n^3)  优化后O(n^2)

代码实现:

 /**
     *
     *  暴力法求最大子数组的和问题
     *  时间复杂度n(n^3)
     * @return
     */
    public static int maxSubArray(int arr[]){
        int n = arr.length;//数组大小
        int ThisSum = 0;//记录主数组的和
        int MaxSum = 0;//记录最大子数组的和
        int i,j,k;
        for (i=0;i<n;i++){//记录子数组的底
            for(j=0;j<n;j++){//记录子数组的高
                ThisSum =0;
                for (k=0;k<j;k++){//计算所遍历出来的子数组的和
                    ThisSum+=arr[k];
                }
                if (ThisSum > MaxSum){//找出最大的子数组
                    MaxSum = ThisSum;
                }
            }

        }
        return MaxSum;
    }

    /**
     * 时间复杂度O(n^2)
     * @param arr
     * @return
     */
    public static int maxSubArray1(int arr[]){
        int size = arr.length;
        int maxSum = Integer.MIN_VALUE;
        for(int i = 0; i<size; i++){
            int sum = 0;
            for (int j=i;j<size;j++){
                sum+=arr[j];
                if (sum>maxSum){
                    maxSum = sum;
                }
            }
        }
        return maxSum;
    }

动态规划法:

算法思路:根据数组中最后一个元素arr[n-1]与最大子数组的关系分为以下三种情况:
   1、最大子数组中包含arr[n-1],以arr[n-1]结尾
   2、arr[n-1]单独构成最大子数组
   3、最大子数组中不包含arr[n-1],求arr[1,...,n-1]的最大子数组转化为求arr[1,...,n-2]的最大子数组
   假设:
   (arr[0],...,arr[i-1])的最大的一段数组和为nAll
   (arr[0],...,arr[i-1])包含arr[i-1]的最大的一段数组和为nEnd
   得出关系:
   nAll = max{arr[i-1],nEnd(i-1),nAll(不包括arr[i-1]的最大子数组)}

时间复杂度: O(n)

空间·复杂度O(n)

代码实现:

/**
   *  时间复杂度O(n)
   *  空间复杂度O(n)
   * 方法描述:
   * 根据数组中最后一个元素arr[n-1]与最大子数组的关系分为以下三种情况:
   * 1、最大子数组中包含arr[n-1],以arr[n-1]结尾
   * 2、arr[n-1]单独构成最大子数组
   * 3、最大子数组中不包含arr[n-1],求arr[1,...,n-1]的最大子数组转化为求arr[1,...,n-2]的最大子数组
   * 
   * 假设:
   * (arr[0],...,arr[i-1])的最大的一段数组和为nAll
   * (arr[0],...,arr[i-1])包含arr[i-1]的最大的一段数组和为nEnd
   * 得出关系:
   * nAll = max{arr[i-1],nEnd(i-1),nAll(不包括arr[i-1]的最大子数组)}
   *
   * @param arr
   * @return
   */

    public static int maxSubArray2(int arr[]){
    	int n = arr.length;
    	int End[] = new int[n];
    	int All[] = new int[n];
    	End[n-1] = arr[n-1];
    	All[n-1] = arr[n-1];
    	End[0]=All[0]=arr[0];
    	for (int i = 0; i < n; i++) {
			End[i] = max(End[i-1], End[i-1]+arr[i]);
			All[i] = max(End[i], All[i-1]);
		}
    	return All[n-1];
    }

    /**
     * 思路同上
     * 上述思路只用到End[i-1]和All[i-1],而不是数组中全部的值,
     * 所以可以定义两个变量来保存End[i-1]和All[i-1]的值,
     * 并可以反复调用
     * 空间复杂度降低
     * @param arr maxSubArray22
     * @return
     */
    public static int maxSubArray22(int[] arr){
    	int n = arr.length;
    	int nAll = arr[0];
    	int nEnd = arr[0];
    	for (int i = 0; i < n; i++) {
			nEnd = max(nEnd+arr[i], arr[i]);//单独的arr[i]与包含arr[i]的最大子数组和比较,较大值赋给nEnd
			nAll = max(nEnd, nAll);//nEnd与不包含arr[i]的数组进行比较得出最终的最大值
		}
    	return nAll;
    }

    /**
     * 获取较大的值
     * @param m
     * @param n
     * @return
     */
    public static int max(int m ,int n){
    	return m>n?m:n;
    }
    

扩展:确定最大子数组的位置

算法思路:当End[i-1]<0时,End[i]=array[i];子数组从i开始

代码实现:

         private static int begin = 0;//最大子数组起始位置
	 private static int end = 0;//最大子数组结束位置
	 
	 /**
	  * 确定最大子数组的位置
	  * @param arr
	  * @return
	  */
	 public static int maxSubArray3(int arr[]){
		 int maxSum = Integer.MIN_VALUE;
		 int nSum = 0;
		 int nStart = 0;
		 for (int i = 0; i < arr.length; i++) {
			if (nSum<0) {//End[i-1]<0,子数组从i重新开始
				nSum = arr[i];
				nStart = i;
			}
			else {
				nSum += arr[i];
			}
			if (nSum > maxSum) {
				maxSum = nSum;//记录最大子数组
				begin = nStart;//此时子数组的开始值
				end = i;//此时子数组的结束值
			}
		}
		 return maxSum;
	 }
	 }

完整代码为:

package JBArray;


public class MaxSubArrary {


	 private static int begin = 0;//最大子数组起始位置
	 private static int end = 0;//最大子数组结束位置
	 
	 /**
	  * 确定最大子数组的位置
	  * @param arr
	  * @return
	  */
	 public static int maxSubArray3(int arr[]){
		 int maxSum = Integer.MIN_VALUE;
		 int nSum = 0;
		 int nStart = 0;
		 for (int i = 0; i < arr.length; i++) {
			if (nSum<0) {//End[i-1]<0,子数组从i重新开始
				nSum = arr[i];
				nStart = i;
			}
			else {
				nSum += arr[i];
			}
			if (nSum > maxSum) {
				maxSum = nSum;//记录最大子数组
				begin = nStart;//此时子数组的开始值
				end = i;//此时子数组的结束值
			}
		}
		 return maxSum;
	 }
   
    /**
     *
     *  暴力法求最大子数组的和问题
     *  时间复杂度n(n^3)
     * @return
     */
    public static int maxSubArray(int arr[]){
        int n = arr.length;//数组大小
        int ThisSum = 0;//记录主数组的和
        int MaxSum = 0;//记录最大子数组的和
        int i,j,k;
        for (i=0;i<n;i++){//记录子数组的底
            for(j=0;j<n;j++){//记录子数组的高
                ThisSum =0;
                for (k=0;k<j;k++){//计算所遍历出来的子数组的和
                    ThisSum+=arr[k];
                }
                if (ThisSum > MaxSum){//找出最大的子数组
                    MaxSum = ThisSum;
                }
            }

        }
        return MaxSum;
    }

    /**
     * 时间复杂度O(n^2)
     * @param arr
     * @return
     */
    public static int maxSubArray1(int arr[]){
        int size = arr.length;
        int maxSum = Integer.MIN_VALUE;
        for(int i = 0; i<size; i++){
            int sum = 0;
            for (int j=i;j<size;j++){
                sum+=arr[j];
                if (sum>maxSum){
                    maxSum = sum;
                }
            }
        }
        return maxSum;
    }
    
  /**
   * 时间复杂度O(n)
   * 方法描述:
   * 根据数组中最后一个元素arr[n-1]与最大子数组的关系分为以下三种情况:
   * 1、最大子数组中包含arr[n-1],以arr[n-1]结尾
   * 2、arr[n-1]单独构成最大子数组
   * 3、最大子数组中不包含arr[n-1],求arr[1,...,n-1]的最大子数组转化为求arr[1,...,n-2]的最大子数组
   * 
   * 假设:
   * (arr[0],...,arr[i-1])的最大的一段数组和为nAll
   * (arr[0],...,arr[i-1])包含arr[i-1]的最大的一段数组和为nEnd
   * 得出关系:
   * nAll = max{arr[i-1],nEnd(i-1),nAll(不包括arr[i-1]的最大子数组)}
   * 
   * @param arr
   * @return
   */
    public static int maxSubArray2(int[] arr){
    	int n = arr.length;
    	int nAll = arr[0];
    	int nEnd = arr[0];
    	for (int i = 0; i < n; i++) {
			nEnd = max(nEnd+arr[i], arr[i]);//单独的arr[i]与包含arr[i]的最大子数组和比较,较大值赋给nEnd
			nAll = max(nEnd, nAll);//nEnd与不包含arr[i]的数组进行比较得出最终的最大值
		}
    	return nAll;
    }

    /**
     * 获取较大的值
     * @param m
     * @param n
     * @return
     */
    public static int max(int m ,int n){
    	return m>n?m:n;
    }
    
    
   

    public static  void main(String[] args){
        int[] arr = {1,-2,4,8,-4,7,-1,-5};
        System.out.println(maxSubArray(arr));
        System.out.println(maxSubArray2(arr));
    }

}

求数对之差的最大值(与上述类似)

暴力法::

动态规划:
     *  时间复杂度O(n)
     *  空间复杂度O(n)
     *  a:数组
     *  diff[i] 以i为减数的所有对数之差的最大值
     *  max[i] 前i+1个数的最大值
     *  diff[i+1]有两种可能性:
     *        diff[i];
     *        max[i]-a[i]
     *  动态规划的计算表达式为:
     *        diff[i+1] = max(diff[i],max[i]-a[i])
     *        max[i+1]= max(max[i],a[i+1])

动态规划的空间优化:
     * 思路同上
     * 上述思路只用到diff[i]和max[i],而不是数组中全部的值,
     * 所以可以定义两个变量来保存diff[i]和max[i]的值,
     * 并可以反复调用
     * 空间复杂度降低

package JBArray;
/**
 * 求数对之差的最大值
 * @author Dan
 *
 */

public class Maxnum {
	
	/**
	 * 蛮力法
	 */
	public static int getMax(int[] a){
		if(a==null){
			return Integer.MIN_VALUE;
		}
		int len = a.length;
		if (len<=1) {
			return Integer.MIN_VALUE;
		}
		int max = Integer.MIN_VALUE;
		for (int i = 0; i < len-1; i++) {
			for (int j = i+1; j < len; j++) {
				if (a[i]-a[j]>max) {
					max = a[i]-a[j];
				}
			}
		}
		return max;
	}

	/**
	 *  动态规划法
	 *  时间复杂度O(n)
	 *  空间复杂度O(n)
	 *  a:数组
	 *  diff[i] 以i为减数的所有对数之差的最大值
	 *  max[i] 前i+1个数的最大值
	 *  diff[i+1]有两种可能性:
	 *        diff[i];
	 *        max[i]-a[i]
	 *  动态规划的计算表达式为:
	 *        diff[i+1] = max(diff[i],max[i]-a[i])
	 *        max[i+1]= max(max[i],a[i+1])
	 * @param a
	 * @return
	 */
	public static int getMax1(int[] a){
		if(a == null)
			return Integer.MIN_VALUE;
		int len = a.length;
		if (len<=1) {
			return Integer.MIN_VALUE;
		}
		int[] diff = new int[len];
		int[] max = new int[len];
		diff[0]=Integer.MIN_VALUE;
		max[0] = a[0];
		for(int i = 1;i < len; i++){
			diff[i]= Max(diff[i-1],max[i-1] - a[i]);
			max[i] = Max(max[i-1],a[i]);
		}
		return diff[len-1];
	}
	
	/**
	 * 思路同上
     * 上述思路只用到diff[i]和max[i],而不是数组中全部的值,
     * 所以可以定义两个变量来保存diff[i]和max[i]的值,
     * 并可以反复调用
     * 空间复杂度降低
	 * @param a
	 * @return
	 */
	public static int getMax2(int[] a){
		if(a == null)
			return Integer.MIN_VALUE;
		int len = a.length;
		if (len<=1) {
			return Integer.MIN_VALUE;
		}
		int diff = 0;
		int  max = a[0];
		for(int i = 1;i < len; i++){
			diff= Max(diff,max - a[i]);
			max = Max(max,a[i]);
		}
		return diff;
	}
	
	
	public static int Max(int a ,int b){
		return a > b ? a : b;
	}
	
	public static void main(String[] args) {
		int[] a = {1,4,17,3,2,9};
		System.out.println(getMax(a));
		System.out.println(getMax1(a));
		System.out.println(getMax2(a));
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值