递归:自己调自己
什么时候用递归?将一堆数组分成左右两部分的时候用递归,这两部分又继续分。或者说,递归是当你将一个母问题分成几个子问题才使用,一般情况下是分成两个部分。
递归的时间复杂度求法:
递归满足:T(n)=a*T(n/b)+O(nd)
- a:调用了几次子问题
- b:将母问题分成几个子问题
- d:除了子问题调用之外剩下的过程的时间复杂度
递归时间复杂度:
若logba<d,则O(Nd)
若logba==d,则O(Nd*logN)
若logba>d,则O(Nx), x=logba
用递归方法找到数组中的最大值代码实现:
public class demo {
public static void main(String[] args) {
int[] nums={2,6,12,35,28,98,67};
int start = 0;
int end=nums.length-1;
//定义递归方法,因为要实现自己调自己,所以要传入开始下标和结束下标
int max =process(nums,start,end);
System.out.println(max);
}
public static int process(int[] nums, int start, int end) {
//如果数组中只有一个元素,则最大值就是它自己
if(start==end){
return nums[start];
}
/*
* 先找到左边的最大值,再找到右边的最大值,二者比较就是最大值
* 左边的部分又可以分为两个部分,直到不可分,右边同理
* 解析如下:
* 假设数组里元素为a,b,c,d,e
* 第一次: a,b c,d,e
* 第二次: a b c d,e
* 第三次: d e
* 如上解析,左边部分的最大值就是max(a,b)
* 右边部分的最大值就是max(c,max(d,e))
* */
//中点
//(end-start)>>1这个外面必须加小括号,不然会出现stackoverflowerror栈溢出异常
//为什么会出现栈溢出,是因为算数运算符的优先级比按位运算符的优先级高,若无小括号,则先算加法后按位运算
int middle = start + ((end-start)>>1);
int leftMax = process(nums,start,middle);
int rightMax = process(nums,middle+1,end);
return Math.max(leftMax,rightMax);
}
}
分析上面找最大值的时间复杂度:
母问题:找到nums中最大的数
子问题:找到左边最大的数和右边最大的数,b=2
子问题调用的次数:再process函数中,只出现了两次process方法,所以a=2
剩下的时间复杂度,主函数除了process函数调用,时间复杂度是O(1),process函数除了调用自身,就是有一个比较,时间复杂度O(N),所以d=1
套用前面公式,本题的时间复杂度是O(N*logN)