最大子数组

Divide-and-Conquer

将原问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解。

其大致的步骤可以分为三步:

  • 分解原问题为若干子问题,这些子问题都是原问题规模较小的实例。
  • 解决这些子问题,递归的求解各子问题。
  • 合并这些子问题的解成原问题的解。
最大子数组

数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值。假设要寻找数组为A[start,high]的最大和子数组,其中A[]表示数组,starthigh表示数组的首下标和尾下标。使用分治策略之后,最大和子数组出现的位置可能有如下三种情况:

  • 位于子数组A[start,mid]
  • 位于子数组A[mid+1,high]
  • 子数组的位置跨域中点,此时需要分两部分,中点左边最大,右边最大,那么两者的和加起来就是最大。也就是我们要求的最大子数组。

找寻最大子数组的pseudo-code如下:

FindMaxSubArray(Array,start,end)
    if start == end
        return Array[start]
    else
        mid=[start+end]/2   
        (left_start,left_end,left_sum)=FindMaxSubArray(Array,start,mid)
        (right_start,right_end,right_sum)=FindMaxSubArray(Array,mid+1,end)
        (cross_start,cross_end,cross_sum)=FindCrossSubArray(Array,start,mid,end)
        if left_sum>=right_sum and left_sum >= cross_sum
            return (left_start,left_end,left_sum)
        elseif right_sum>=left_sum and right_sum >=cross_sum
            return (right_start,right_end,right_sum)
        else cross_sum >= left_sum and cross_sum >= right_sum
            return (cross_left,cross_end,cross_sum)
FindCrossSubArray(Array,start,mid,end)
    left_sum=Integer.MIN_VALUE
    sum = 0
    for i=mid downto start
        sum = sum + Array[i]
        if sum > left_sum
            sum = left_sum
            max_left=i
    right_sum=Integer.MIN_VAlUE
    sum=0
    for i = mid+1 to end
        sum=sum+Array[i]
        if sum > right_sum
            sum = right_sum
            max_right=i
    return (max_left,max_right,right_sum+left_sum)

具体的java语言实现如下:

package com.ctw.algorithm;

import java.util.Arrays;

import javax.sound.midi.MidiChannel;

import com.ctw.algorithm.MaxSubarray.SubArray;
//分治法实现求最大子数组
class MaxSubarray
{
    //找到跨越中点的最大和子数组
    public SubArray Find_CrossingSubarray(int[] A,int low , int mid , int high) 
    {
        int left_sum  = Integer.MIN_VALUE;
        int max_left = 0;
        int right_sum = Integer.MIN_VALUE;
        int max_right = 0;
        int sum_left  = 0;
        int sum_right = 0;

        for(int i = mid ; i >= low ; i--) 
        {
            sum_left += A[i];
            if (sum_left > left_sum) {
                left_sum = sum_left;
                max_left = i;
            }
        }
        for(int j = mid+1 ; j <= high ; j++) {
            sum_right += A[j];
            if (sum_right > right_sum ) {
                right_sum = sum_right;
                max_right = j;
            }
        }
        return new SubArray (max_left,max_right,left_sum+right_sum);

    }
class SubArray
{
    int low;
    int high;
    int sum = 0;
    public SubArray(int low , int high , int sum) 
    {
        this.low  = low;
        this.high = high;
        this.sum  = sum;
    }
}
    public SubArray Find_MaxSum(int[] A , int low , int high) 
    {
        if (low == high) {
            return new SubArray(low, high, A[low]);
        }else {
            int mid = (low+high)/2;
            SubArray leftResult = Find_MaxSum(A, low, mid);
            SubArray rightResult = Find_MaxSum(A, mid+1, high);
            SubArray crossResult = Find_CrossingSubarray(A, low, mid, high);
            if(leftResult.sum >= crossResult.sum && leftResult.sum>= rightResult.sum){
                return leftResult;
            }else if (rightResult.sum>= leftResult.sum && rightResult.sum >= crossResult.sum) {
                return rightResult;
            }else {
                return crossResult;
            }
        }

    }
}
public class Max_Sum_array_2 {
    public static void main(String[] args) 
    {
        int[] A = new int[] {1,-5,1,-2,7,-2};
        SubArray B = new MaxSubarray().Find_MaxSum(A, 0, A.length-1);
        System.out.println(B.low+" "+B.high+" "+B.sum);

    }
}

其运行结果为:4 4 7

猜你喜欢

转载自blog.csdn.net/wilder_ting/article/details/78941091
今日推荐