分治策略(算法)

不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!

分治策略

在分治策略中我们递归的求解一个问题,在每层递归中应用如下三个步骤:
分解:将问题划分成为一些子问题的形式,子问题形式与原问题一样,只是规模更小。
解决:递归的求解子问题。如果问题的规模足够小,则停止递归,直接求解。
合并:将子问题的解组合形成原问题的解。

求解递归的O渐近界方法:

【1】猜测代入法
【2】递归树法
【3】主方法 使用公式

最大字数组和的求解

package algorithm.java.ch04;

/**
 * @author LbZhang
 * @version 创建时间:2015年12月21日 下午7:56:23
 * @description 最大子数组的和 问题是这样的:一个整数数组中的元素有正有负,在该数组中找出一个连续子数组,要求该子数组中各元素的和最大,
 *              这个子数组便被称作最大子数组。比如数组{2,4,-7,5,2,-1,2,-4,3}的最大子数组为{5,2,-1,2},
 *              最大子数组的和为5+2-1+2=8。
 */
public class MaxSubArray {
    public static void main(String[] args) {
        int[] numArr = { 2, 4, -7, 5, 2, -1, 2, -4, 3 };
        System.out.println("暴力求解:");
        baoliHandle(numArr);
        System.out.println("线性求解:'");
        linarHandle(numArr);
        System.out.println("分治求解:");
        divHandle(numArr);

    }

    /*
     * 暴力求解办法
     */
    public static int baoliHandle(int[] arr) {
        int i, j;
        int len = arr.length;
        int maxSum = 0;
        int begin = 0, end = 0;
        for (i = 0; i < len; i++) {
            int Cursum = 0;// 每一个作为起点的累加的数据和的临时保存
            for (j = i; j < len; j++) {
                Cursum += arr[j];
                if (Cursum > maxSum) {
                    maxSum = Cursum;
                    begin = i;
                    end = j;
                }
            }

        }
        System.out.println("最大字数组:");
        for (i = begin; i <= end; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
        System.out.println("MaxSum: " + maxSum);
        return maxSum;
    }

    public static int divHandle(int[] arr) {
        SubArray sa = new SubArray();
        sa = findMaxSubArray(sa, arr, 0, arr.length - 1);
        System.out.println("最大字数组:");
        for (int i = sa.getBegin(); i <= sa.getEnd(); i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
        System.out.println("MaxSum: " + sa.getSum());


        return sa.getSum();
    }

    /**
     * 递归调用函数
     * 
     * @param sa
     * @param arr
     * @param i
     * @param j
     */
    private static SubArray findMaxSubArray(SubArray sa, int[] arr, int left,
            int right) {
        if (left == right) {
            sa.setBegin(left);
            sa.setEnd(right);
            sa.setSum(arr[left]);
            return sa;
        } else {
            int mid = (left + right) / 2;
            SubArray saleft = findMaxSubArray(sa, arr, left, mid);
            SubArray saright = findMaxSubArray(sa, arr, left, mid);

            SubArray sacross = findCrossingMaxSubArray(sa, arr, left, mid,
                    right);

            if (saleft.getSum() > saright.getSum()
                    && saleft.getSum() > sacross.getSum()) {
                return saleft;
            } else if (saright.getSum() > saleft.getSum()
                    && saright.getSum() > sacross.getSum()) {
                return saright;
            } else {
                return sacross;
            }
        }
    }

    private static SubArray findCrossingMaxSubArray(SubArray sa, int[] arr,
            int left, int mid, int right) {
        int sum=0;
        int begin=0;
        int end=0;

        int leftsum = 0;
        for(int i=mid;i>=left;i--){
            sum=sum+arr[i];
            if(sum>leftsum){
                leftsum=sum;
                begin=i;
            }
        }
        int rightsum = 0;
        sum=0;
        for(int i=mid+1;i<=right;i++){
            sum=sum+arr[i];
            if(sum>rightsum){
                rightsum=sum;
                end=i;
            }
        }

        sa.setBegin(begin);
        sa.setEnd(end);
        sa.setSum(leftsum+rightsum);

        return sa;
    }

    /**
     * 最优方法,时间复杂度O(n)和最大的子序列的第一个元素肯定是正数因为元素有正有负,因此子序列的最大和一定大于0
     * 
     * @param arr
     * @return
     */
    public static int linarHandle(int[] arr) {
        int i;
        int len = arr.length;
        int maxSum = 0;
        int curSum = 0;
        int begin = 0, end = 0;

        for (i = 0; i < len; i++) {
            curSum += arr[i];
            if (curSum > maxSum) {
                maxSum = curSum;
                end = i;
            }
            // 如果累加和出现小于0的情况,
            // 则和最大的子序列肯定不可能包含前面的元素
            // 这时将累加和置0,从下个元素重新开始累加
            if (curSum < 0) {
                curSum = 0;
                begin = i + 1;// 最小从下一个开始
            }
        }

        System.out.println("最大字数组:");
        for (i = begin; i <= end; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
        System.out.println("MaxSum: " + maxSum);

        return maxSum;

    }

}

运行结果:
程序执行结果

posted @ 2015-12-21 10:38  snowwolf101  阅读(417)  评论(0编辑  收藏  举报