求最大子数组的和并确定子数组的位置

求最大子数组之和

蛮力法:

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

时间复杂度: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)
   * 方法描述:
   * 根据数组中最后一个元素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;
    }
    

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

算法思路:当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));
    }

}

猜你喜欢

转载自blog.csdn.net/hd12370/article/details/81079157