分治法求解最大子数组问题

最大子数组:求连续数组的最大和问题,也就是说数组的那个连续子数组的和最大.(个人理解)

    主要思想通过分治法,最大子数组只能有三种情况:中间元素的左边取得;中间元素的右边取得;跨越中间元素取得.  可以通过mind=(low+high)/2分解,把元问题分解成更小的子问题。

代码如下     ArrarType表示找到的最大子数组相应的左右边界和值

package com.lifeStudy.algorith;

public class ArrarTypes {
    private int max_left;
    private int max_right;
    private int max_sum;

    @Override
    public String toString() {
        return "ArrarTypes:  max_left=" + max_left + "  max_right=" + max_right + "   max_sum=" + max_sum;
    }

    public ArrarTypes(int max_left, int max_right, int max_sum) {
        this.max_left = max_left;
        this.max_right = max_right;
        this.max_sum = max_sum;
    }

    public void setMax_left(int max_left) {
        this.max_left = max_left;
    }

    public void setMax_right(int max_right) {
        this.max_right = max_right;
    }

    public void setMax_sum(int max_sum) {
        this.max_sum = max_sum;
    }

    public int getMax_left() {
        return max_left;
    }

    public int getMax_right() {
        return max_right;
    }

    public int getMax_sum() {
        return max_sum;
    }
}

 

 

求解算法代码

package com.lifeStudy.algorith;


//求解最小子数组问题  分治法
public class TheMaxSubArray {


    /**
     * @param A    待求数组
     * @param low  最小的位置序列
     * @param mid  中间的位置序列
     * @param high 最大的位置序列
     * @return 返回数组A 中跨越中间位置的最大数组和  包括起始和结束边界、最大的和值
     */

    //求出数组A跨越中点mid的最大数组和
    public static ArrarTypes find_max_crossing_subArray(int[] A, int low, int mid, int high) {


        //求出左边数据的最大和
        int left_sum = Integer.MIN_VALUE;
        int max_left = mid;//记录左边最大和的边界位置
        int sum = 0;
        for (int i = mid; i >= low; i--) {
            sum += A[i];
            if (sum > left_sum) {
                left_sum = sum;
                max_left = i;
            }
        }
        //求出右边数据的最大和

        int right_sum = Integer.MIN_VALUE;
        int max_right = mid + 1;
        sum = 0;
        for (int j = mid + 1; j <= high; j++) {

            sum += A[j];
            if (sum > right_sum) {
                right_sum = sum;
                max_right = j;
            }
        }
        return new ArrarTypes(max_left, max_right, left_sum + right_sum);
    }

    /**
     * @param A    目标数组
     * @param low  数组最小位置
     * @param high 数组最大位置
     * @return
     */
    //查找出最大和数组  包含三种情况 在数组集合的左边;在数组集合的右边;跨越数组中心元素集合
    public static ArrarTypes find_max_subArray(int[] A, int low, int high) {

        if (low > high) {
            return null;
        }
        if (low == high) {
            return new ArrarTypes(low, high, A[low]);
        } else {
            int mid = (low + high) / 2;
            ArrarTypes max_subArrayleft = find_max_subArray(A, low, mid);
            ArrarTypes max_subArrayright = find_max_subArray(A, mid + 1, high);
            ArrarTypes max_crossing_subArray = find_max_crossing_subArray(A, low, mid, high);
            if (max_crossing_subArray.getMax_sum() > max_subArrayleft.getMax_sum() && max_crossing_subArray.getMax_sum() > max_subArrayright.getMax_sum()) {
                return max_crossing_subArray;
            } else if (max_subArrayleft.getMax_sum() > max_crossing_subArray.getMax_sum() && max_subArrayleft.getMax_sum() > max_subArrayright.getMax_sum()) {
                return max_subArrayleft;
            } else{
                return max_subArrayright;
            }
        }

    }


    public static void main(String... args) {
        int a[] = new int[]{13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};
        ArrarTypes max_subArray = find_max_subArray(a, 0, a.length - 1);
        System.out.println(max_subArray.toString());
    }


}

 

   线性时间实现求最大子数组问题·

   原理:例如A[1.....j]的最大子数组已知,那么A[1......j+1]的最大子数组要么是前一个元素的最大子数组,或者是A[i....j+1]为最大子数组
              可以通过比较前一个最大子数组和边界最大子数组(包含最后一个元素) 的大小

package com.lifeStudy.algorith;

//求线性时间的最大子数组问题
public class TheMaxSubArrayLinearTime {
    //原理:例如A[1.....j]的最大子数组已知,那么A[1......j+1]的最大子数组要么是前一个元素的最大子数组,或者是A[i....j+1]为最大子数组
    private static int[] boundryMax;//边界最大子数组   当前元素的最大子数组等于前一个元素的最大子数组或者前一个元素的边界子数组加当前元素或者等于当前元素
    private static int[] valueMax;//最大子数组
    private static int[][] pos;//最大子数组的边界位置信息

    public static void InitDatas(int vales[]) {

        boundryMax = new int[vales.length];
        valueMax = new int[vales.length];
        //初始化第一个元素的边界最大子数组和最大子数组
        boundryMax[0] = vales[0];
        valueMax[0] = vales[0];
        pos = new int[vales.length][2];
        pos[0][1] = pos[0][0] = 0;
        //求出每一个子数组的最大子数组
        for (int i = 1; i < vales.length; i++) {
            int beforeValueMax = valueMax[i - 1];//前一个最大子数组
            int currentValue = vales[i];
            int beforeBoundryMax = boundryMax[i - 1] + currentValue;
            int max = beforeValueMax > currentValue ? (beforeValueMax > beforeBoundryMax ? beforeValueMax : beforeBoundryMax) : (currentValue > beforeBoundryMax ? currentValue : beforeBoundryMax);
            valueMax[i] = max;
            boundryMax[i] = beforeBoundryMax > currentValue ? beforeBoundryMax : currentValue;
        }
    }

    public static void main(String... args) {
        int a[] = new int[]{13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7, 0};
        InitDatas(a);
        System.out.println(valueMax[valueMax.length - 1]);
    }
}

 

posted @ 2018-03-20 21:29  张秀杰  阅读(782)  评论(0编辑  收藏  举报