求浮点数数组A={A1,A2,A3,…,An}中,Aj-Ai(j>i)的最大值。要求时间复杂度越小越好。
1、问题分析:
如果没有时间现在,那么直接使用两层for循环,就能搞定问题。其代码大致如下:
Code::
int find_max_diff_slow(int *array,int len) { int i=len-1,j=0,ret=0,diff=0; if(len==2)return array[1]-array[0]; if(len<=1)return -1; ret=array[len-1]-array[len-2]; for(i=len-1;i>0;i--) { for(j=i-1;j>0;j--) { diff=array[i]-array[j]; if(ret<diff)ret=diff; } } return ret; } |
采用find_max_diff_slow的时间复杂度为O(n^2)
那么有没有更快的方法呢?有!
http://topic.youkuaiyun.com/u/20070917/19/de6931d2-18a4-4f0e-ac83-89f9e597c32d_3.html
方法来自上面这个链接。这个链接主题讨论了数组两两之差的绝对值最小的求解问题,和本文中的问题有些出入,不过思想都是一样的,即转换!那么如何转换呢?
2、另一问题
在进一步讨论问题转换前,先看看另外一个问题:
求n个浮点数向量的连续的任何子向量的最大和。
例如[31,-41,59,26,-53,58,97,-93,-23,84],最大和为:59+26-53+59+97=187
根据《编程珠玑》中的介绍,这个问题可以在O(n)的条件下得到解答。
Code::
int max_sum_of_subarray(int *array,int len) { int i=0,maxendinghere=0,maxsofar=0; for(i=0;i<len;++i) { maxendinghere=(maxendinghere+array[i])>0?maxendinghere+array[i]:0; maxsofar=(maxendinghere>maxsofar)?maxendinghere:maxsofar; } return maxsofar; } |
3、问题的转换
现在我们看看如何求解这个问题。
对于数组A={A1,A2,A3,….,An},构造数组B,使得对于任意的Bi(i=1,2,3,…,n-1)满足如下条件:
Bi=An-i-1-An-i
即:
B1=An-An-1;
B2=An-1-An-2;
。。。。。。。。。
Bn-1=A2-A1;
对于任意的Aj-Ai(j>i)有如下公式成立:
Aj-Ai=Aj-Aj-1+Aj-1-Aj-2+…+Ai+2-Ai+1+Ai+1-Ai=Bk+Bk+1+…+Bp
其中k=n-j+1,p=n-i+1;
所以问题就转换为求数组B的连续子向量的最大和问题了,这个正式【2】中的正解!
4、代码和结果
int find_max_diff(int *array,int len) { int *diff_array=new int[len-1]; int i=0,j=0; for(i=len-1,j=0;i>0;i--,j++) { diff_array[j]=array[i]-array[i-1]; } int ret=max_sum_of_subarray(diff_array,len-1); delete []diff_array; return ret; }
void test_max_sum_of_subarray() { int array[]={31,-41,59,26,-53,58,97,-93,-23,84}; cout<<"max_sub_sum::"<<max_sum_of_subarray(array,10)<<endl; int array1[]={7,8,4,6,3,9}; cout<<find_max_diff(array1,6)<<endl; cout<<find_max_diff_slow(array1,6)<<endl; } |