题目:在数组中,数字减去它右边的数字得到一个数对之差。求所有数对之差的最大值。例如在数组{2, 4, 1, 16, 7, 5, 11, 9}中,数对之差的最大值是11,是16减去5的结果。
分治策略:
通常蛮力法不会是最好的解法,我们想办法减少减法的次数。假设我们把数组分成两个子数组,我们其实没有必要拿左边的子数组中较小的数字去和右边的子数组中较大的数字作减法。我们可以想象,数对之差的最大值只有可能是下面三种情况之一:(
1)被减数和减数都在第一个子数组中,即第一个子数组中的数对之差的最大值;(2)被减数和减数都在第二个子数组中,即第二个子数组中数对之差的最大值;(3)被减数在第一个子数组中,是第一个子数组的最大值。减数在第二个子数组中,是第二个子数组的最小值。这三个差值的最大者就是整个数组中数对之差的最大值。
在前面提到的三种情况中,得到第一个子数组的最大值和第二子数组的最小值不是一件难事,但如何得到两个子数组中的数对之差的最大值?这其实是原始问题的子问题,我们可以递归地解决。下面是这种思路的参考代码:
#include <iostream>
using namespace std;
int MaxDiffCore(int* start,int* end,int* max,int* min){//分之策略
if(end == start){//递归用法的前提
*max = *min = *start;
return 0;
}
int* middle = start+(end-start)/2;
int maxLeft,minLeft;
int leftDiff = MaxDiffCore(start,middle,&maxLeft,&minLeft);
int maxRight,minRight;
int rightDiff = MaxDiffCore(middle+1,end,&maxRight,&minRight);
int crossDiff = maxLeft -minRight;
*max = (maxLeft>maxRight)?maxLeft:maxRight;//求的每个递归点的值
*min = (minLeft<minRight)?minLeft:minRight;
int maxDiff2 = (leftDiff>rightDiff)?leftDiff:rightDiff;
return (maxDiff2>crossDiff)?maxDiff2:crossDiff;
}
int MaxDiff_Solution(int numbers[],unsigned length){
if(NULL==numbers || length <2)
return 0;
int max,min;
return MaxDiffCore(numbers,numbers+length-1,&max,&min);
}
int main(){
const int N = 10;
int array[N] = {2,4,1,16,7,5,11,9,5,1};
cout << "MaxDiff: " << MaxDiff_Solution(array,N) << endl;
return 0;
}
运行结果:
MaxDiff: 15