1. 程式人生 > >4.1 最大子陣列問題(分治法)-NlogN

4.1 最大子陣列問題(分治法)-NlogN

A[low..high]的任何子陣列A[i,j]所處的位置必定是一下三種情況之一:

  • 完全位於子陣列A[low..mid]中,low< =i<=j<=mid
  • 完全位於子陣列A[mid+1..high]中,mid < i< =j< =high
  • 跨越了中點,low< =i< =mid < j< =high

思路:

  1. 遞迴地求解A[low..mid]和A[mid+1..high]的最大子陣列
  2. 尋找跨越中點的最大子陣列
  3. 選取這三中情況中的最大值

1.尋找跨越中點的最大子陣列

/***
     * 
     * @param
A 陣列 * @param low 下界 * @param mid 中點 * @param high 上界 * @return 最大子陣列(跨越mid)的下標範圍和最大子陣列的和 */
public static int[] findMaxCrossingSubArray ( int[] A, int low, int mid, int high ) { //找出左半部的最大子陣列,必須包括A[mid]
int left_sum=0; //目前找到的最大和 int sum=0; //A[i..mid]的和 int max_left=mid; //目前找到的最大和的下標 for (int i = mid; i >=low; i--) { sum=sum+A[i]; if (sum>left_sum) { left_sum=sum; max_left=i; } } //找出右半部的最大子陣列,必須包括A[mid]
int right_sum=0; //目前找到的最大和 sum=0; //A[mid+1..i]的和 int max_right=mid; //目前找到的最大和的下標 for (int j = mid+1; j <= high; j++) { sum=sum+A[j]; if (sum>right_sum) { right_sum=sum; max_right=j; } } //返回結果 return new int[]{max_left,max_right,left_sum+right_sum}; }

2.遞迴地求解A[low..mid]和A[mid+1..high]的最大子陣列,選取這三中情況中的最大值

public static int[] findMaximumSubArray(int[] A,int low,int high)
{
    //只有一個元素
    if (high==low) {
        return new int[]{low,high,A[low]};
    }
    else {
        int mid=(low+high)/2;
        int[] left_result =findMaximumSubArray(A,low,mid);
        int[] right_result=findMaximumSubArray(A,mid+1,high);
        int[] mid_result  =findMaxCrossingSubArray(A,low,mid,high);
        if(left_result[2]>=right_result[2]
                &&left_result[2]>=mid_result[2]) 
        {
            return left_result;
        }else if (right_result[2]>=left_result[2]
                &&right_result[2]>=mid_result[2]) 
        {
            return right_result;
        }else {
            return mid_result;
        }       
    }
}