Divide-and-Conquer
将原问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解。
其大致的步骤可以分为三步:
- 分解原问题为若干子问题,这些子问题都是原问题规模较小的实例。
- 解决这些子问题,递归的求解各子问题。
- 合并这些子问题的解成原问题的解。
最大子数组
数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值。假设要寻找数组为A[start,high]
的最大和子数组,其中A[]
表示数组,start
和high
表示数组的首下标和尾下标。使用分治策略之后,最大和子数组出现的位置可能有如下三种情况:
- 位于子数组
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