问题:给定一个长度为N的数组arr[0,N-1],使用递归算法求最大值,并计算时间复杂度
编码:
public static int process(int arr[],int l,int R){//arr代表数组,L代表最小下标,R代表最大下标
if(L==R){
return arr[L];//如果数组内只有一个元素,那最大值就是这个数
}
int mid=L+((R-L)>>1);
int leftMax=process(arr,L,mid);
int rightMax=process(arr,mid+1,R);
return Math.max(leftMax,rightMax);
}
代码解释:
int mid=L+((R-L)>>1);
//取数组范围的中间数
//如果使用传统的(L+R)/2,当数组内的元素非常大,接近int的最大值,此时如果我想取数组中间范围的最大值
//那么就很可能会造成溢出,溢出之后再除2就会报错,所以选择先用R-L,然后除2,再加上L,得出的就是中间数
//比如范围是[10000,20000],那么计算过程就是20000-10000然后除2得到5000,加上L得到15000即为中间数
//至于除2为什么使用右移一位,因为右移一位相当于除2,但是比直接除2效率要高,对应的,左移一位就相当于乘2
int leftMax=process(arr,L,mid);
//取到中间数之后,再将L到中间数作为一个范围,重复调用process,直到返回一个最大值
int rightMax=process(arr,mid+1,R);
//取到中间数之后,再将中间数到R作为一个范围,重复调用process,直到返回一个最大值
上面两句代码,转换为流程图理解如下
Master公式
T(N)=a*T(N/b)+O(N^d)
理解:其中 a >= 1 and b > 1 是常量,其表示的意义是n表示问题的规模,a表示递归的次数也就是生成的子问题数,b表示每次递归是原来的1/b之一个规模,f(n)表示分解和合并所要花费的时间之和。
条件:想要使用这个公式,必须满足一个条件,所有的子方法的规模必须相同
计算方法:
①当d<logb^a时,时间复杂度为O(n^(logb^a))
②当d=logb^a时,时间复杂度为O((n^d)*logn)
③当d>logb^a时,时间复杂度为O(n^d)
以上面的递归方法为例:子方法为process,int leftMax=process(arr,L,mid);
调用了一次process,规模为N/2,因为将数组平均分为两半,int rightMax=process(arr,mid+1,R);
调用了一次process,规模也是N/2,剩下的只是Math.max(leftMax,rightMax);
作了一次比较,没有进行循环,所以时间复杂度为O(N^0)=1,这就满足了上面master的条件,a为2(两次子方法),b为1/2(规模为1/2),d为0,所以得到的master公式为T(N)=2*T(2/N)+O(1).
根据计算方法,d=0,loga^b=loga/logb=log2/log2=1
,所以时间复杂度为O(N)