您的位置:首页 > 其它

最大子数组问题

2015-03-17 11:24 239 查看
package com.algorithm.sort;

/**
 * Created by louis on 2015/3/16.
 */

// 最大子数组问题 该类中采用三种方法求解
public class MaxSubArray {

    /*
        暴力求解:先找出从第1个元素开始的最大子数组,而后再从第2个元素开始找出从第2个
                 元素开始的最大子数组,依次类推,比较得出最大的子数组。

        T(n)=O(n^2)
     */
    public static int bruteForce(int[] data){
        int max=0;
        for (int i = 0; i < data.length-1; i++) {
            int curSum=0;
            for (int j = i; j < data.length - 1; j++) {
                curSum += data[j];
                if (curSum > max) {
                    max=curSum;
                }
            }
        }
        return max;
    }

    /*
        分治求解:假定数组 A[low..high],将数组A从中间分为两个字数组A[low..mid]和A[mid+1,high],
                 那么任意连续的字数组A[i..j]一定位于一下三个位置
        (1) 完全位于子数组 A[low..mid],即 low<=i<=j<=high
        (2) 完全位于子数组 A[mid+1..high],即 mid<i<=j<=high
        (3) 位于跨域中点,即 low<=i<=mid<=j<=high

        时间复杂度: T(n)=2T(n/2)+O(n), 递推得到 T(n)=O(nlgn)

        Pseudo code:

        find-maximum-subArray(A,low,high){
            if high==low
                return (low,high,A[low])
            else
                mid=(low+high)/2
                (left-low,left-hig,left-sum)=
                    find-maximum-subArray(A,low,mid)
                (right-low,right-high,right-sum)=
                    find-maximum-subArray(A,mid+1,high)
                (cross-low,cross-high,cross-sum)=
                    find-max-crossing-subArray(A,low,mid,high)
                if left-sum>=right-sum && left-sum>=cross-sum
                    return (left-low,left-high,left-sum)
                else if right-sum>=left-sum && right-sum>=cross-sum
                    return (right-low,right-high,right-sum)
                else
                    return (cross-low,cross-high,cross-sum)
        }

     */
    public static int findMaximumSubArray(int[] data,int low,int high){
        if(low==high){
            return data[low];   // base case: only one element
        }else{
            int mid=(low+high)/2;
            int leftSum = findMaximumSubArray(data, low, mid);
            int rightSum = findMaximumSubArray(data, mid + 1, high);
            int crossSum = findMaxCrossSubArray(data, low, mid, high);
            if (leftSum >= rightSum && leftSum >= crossSum) {
                return leftSum;
            }else if(rightSum>=leftSum&&rightSum>=crossSum){
                return rightSum;
            }else{
                return crossSum;
            }
        }

    }

    /*
        Pseudo code:

        find-max-cross-subArray(A,low,mid,high){
            left-sum=-Infinite
            sum=0
            for i=mid downTo low
                sum+=A[i]
                if sum>left-sum
                    left-sum=sum
                    max-left=i
            right-sum=-Infinite
            sum=0
            for j=mid+1 to high
                sum+=sum[j]
                if sum>right-sum
                    right-sum=sum
                    max-right=j
            return (max-left,max-right,left-sum+right-sum)
        }

     */
    private static int findMaxCrossSubArray(int[] data, int low, int mid, int high) {
        int leftSum = Integer.MIN_VALUE;
        int sum=0;
        int maxLeft; //left max index
        int maxRight;
        for (int i = mid; i >= low; i--) {
            sum += data[i];
            if (sum > leftSum) {
                leftSum=sum;
                maxLeft=i;  // marker the index; no use
            }
        }
        int rightSum = Integer.MIN_VALUE;
        sum=0;
        for (int j = mid + 1; j <= high; j++) {
            sum += data[j];
            if (sum > rightSum) {
                rightSum=sum;
                maxRight=j;
            }
        }
        return leftSum + rightSum;
    }

    /*
        线性时间算法:该算法在每次元素累加和小于0时,从下一个元素重新开始累加;
                    因为元素有正有负,因此子序列的最大和一定大于0;

        该算法只对数据进行一次扫描,一旦元素被读入并被处理,它就不再需要被记忆
        因此,如果数组在磁盘或磁带上,他就可以被顺序读入,在主存中不必存储数组的任何部分。
        不仅如此,在任意时刻,该算法都能对它已经读入的数据给出最大子数组(另外两种算法不具有这种特性)。
        具有这种特性的算法叫做联机算法。

        时间复杂度:T(n)=O(n) 最优算法
     */
    public static int linearTime(int[] data){
        int maxSum=Integer.MIN_VALUE;
        int curSum=0;
        for (int i = 0; i < data.length; i++) {
            curSum += data[i];
            if (curSum > maxSum) {
                maxSum=curSum;
            }
            if (curSum < 0) {
                curSum = 0;
            }
        }
        return maxSum;
    }

    public static void main(String[] args) {
        int[] data = new int[]{13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};
        int max=0;
//        max = MaxSubArray.bruteForce(data);
//        max = MaxSubArray.findMaximumSubArray(data, 0, data.length - 1);
        max = MaxSubArray.linearTime(data);
        System.out.println(max);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: