【算法导论学习-007】最大子数组和问题(Maximum subarray problem)

  问题来源:【算法导论】P68 4.1节,求得一个数组中连续的子数组中最大的和。

  方案1——【算法导论】70页:暴力方法

<pre name="code" class="java"><span style="font-size:18px;">/*暴力方法*/
    public static int[] forceMethod(int[] array) {
        int sum=Integer.MIN_VALUE;
        int tempSum=0;
        int start=-1;
        int end=-1;
        int i=0;
        for (i = 0; i < array.length; i++) {
           /*不要写成j=i+1*/
            for (int j = i; j < array.length; j++) {
                tempSum=0;
                for (int k = i; k <=j; k++) {
                    tempSum+=array[k]; 
                }
                if (tempSum>sum) {
                    sum=tempSum;
                    end=j;
                    start=i;
                }
            }    
        }
        int[] result={start,end,sum};
        return result; 
    }</span>


 
方案2—— 
【算法导论】72页:分治法(复杂度O(nlgn)) 

public class FindMaxSubArray {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        int[] array={4,-3,2};
        int[] result=FindMaxMumSubarray(array, 0,array.length-1);
        System.out.println("起点位置:"+result[0]+";终止位置:"+result[1]+";最大子数组和:"+result[2]);
 
    }
   
    public static int[] FindMaxMumSubarray(int[] array,int low,int high) {
        int[] leftResult;
        int[] rightResult;
        int[] crossResult;
        /*终止条件*/
        if (low==high) {
            int[] result={low,high,array[low]};
            return result;
        }
        else {
            int mid=(high-low)>>>1;
            /*寻找左数组中的最大子数组*/
            leftResult=FindMaxMumSubarray(array, low, mid);
            /*寻找右数组中的最大子数组*/
            rightResult=FindMaxMumSubarray(array, mid+1, high);
            /*寻找跨越中间位置的最大子数组*/
            crossResult=FindMaxCrossingSubArray(array, low, mid, high);
            /*比较三者谁最大,最大的返回*/
            if (leftResult[2]>=rightResult[2]&&leftResult[2]>=crossResult[2]) {
                return leftResult;
            }else if (rightResult[2]>=leftResult[2]&&rightResult[2]>=crossResult[2]) {
                return rightResult;
            }else {
                return crossResult;
            }
        }
    }
    /*寻找跨越中间点的最大子数组,返回值为左位置、有位置、数组和*/
    public static int[] FindMaxCrossingSubArray(int[] array,int low,int mid,int high) {
        int leftSum=Integer.MIN_VALUE;
        int sum=0;
        int maxLeft=Integer.MIN_VALUE;
        for (int i = mid; i >=low; i--) {
            sum+=array[i];
            if (sum>leftSum) {
                leftSum=sum;
                maxLeft=i;
            }  
        }
        int rightSum=Integer.MIN_VALUE;
        sum=0;
        int maxRight=Integer.MIN_VALUE;
        for (int i = mid+1; i <=high; i++) {
            sum+=array[i];
            if (sum>rightSum) {
                rightSum=sum;
                maxRight=i;
            }
        }
        int[] result={maxLeft,maxRight,leftSum+rightSum};
        return result;
    }
}
方案3—— Kadane's algorithm(复杂度O(n))

     参考:http://en.wikipedia.org/wiki/Maximum_subarray_problem

    思路,设置辅助的和auxiliarySum,如果auxiliarySum小于0表明需要重置为下一个,否则累加,只要sum<auxiliarySum就表明需要更新sum

public class Test {
    public static void main(String[] args) {
        int[] a = { 1, -2, 3, 10, -4, 7, 2, -5 };
        System.out.println("最大子数组的下标为" + getMaxSumofArray(a)[0] + ":"
                + getMaxSumofArray(a)[1] + ",和为:" + getMaxSumofArray(a)[2]);
    }
 
    public static int[] getMaxSumofArray(int[] args) {
        int sum = 0;
        int auxiliarySum = 0;
        int from = 0;
        int end = 0;
        for (int i = 0; i < args.length; i++) {
            /*关键点1:和为小于0表明需要重置开始位置,重新计算*/
            if (auxiliarySum < 0) {
                auxiliarySum = args[i];
                from = i;
            } else {
                auxiliarySum += args[i];
            }
            /*关键点2:如果暂时加了负数,auxiliarySum<sum,如果再加正数导致auxiliarySum>sum则更新sum*/
            if (sum < auxiliarySum) {
                sum = auxiliarySum;
                end = i;
            }
        }
        int[] result = { from, end, sum };
        return result;
    }
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值