# 【蓝桥杯备赛】2.递归和常见算法

学了这里,我们会学到1.对递归,建立起感觉2.学会评估算法性能3.能够大致预估程序的执行时间

递归

递归设计经验

  • 找到重复(子问题)
  • 找到重复问题中的变化量->参数
  • 找到参数的变化趋势->设计出口

感受:递归其实有点委托思维:我先做一部分,让递归帮我解决其他部分,然后我进行组合结果。
递归可能分解成:直接量+小规模子问题
也可以分解成多个子问题
递归解答树的顺序是 :先纵深再横
递归的本质其实就是找到==递归公式==

联系策略

  • 循环改递归
  • 经典递归
  • 大量练习,总结规律,掌握套路
  • 找到感觉,挑战高难度

递归训练

求阶乘
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* f1(n):求n的阶乘-->f1(n-1)求n-1的阶乘
* 找重复: n*(n-1)的阶乘,求n-1的阶乘是原问题的重复(规模更小)一子问题
* 找变化:变化的量应该作为参数
* 找边界:出口
*/
static int f(int num ){
if(num==1){
return 1;
}
return f(num -1)*num;
}

打印i-j
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 打印i到j的数字
* 要注意是后生成的递归进程先打印
*/
static void print(int i,int j){
if(j<i){
return;
}
System.out.print(j);
print(i,j-1);
}

数组求和
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 数组求和
* 了解加参数的意识,变化的量要作为参数
*/
static void sum(int[] arr , int i, int sum){
if(i==arr.length){
System.out.println(sum);
return;
}
sum(arr,i+1,sum+arr[i]);
}

翻转字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
	/**
* 翻转字符串
* 思路:翻转abcd,等于翻转bcd+翻转a
* 最后一种切蛋糕思维的题目
*/
static String reverse(String arr){
if(arr.length()==1){
return arr;
}
//把最后一个拼接到前面
return reverse(arr.substring(1))+arr.charAt(0);
}


//多一个参数,不用substring的做法
static String reverse(String arr, int i){
if(i==arr.length()-1){
return arr.charAt(i)+"";
}
return reverse(arr,i+1)+arr.charAt(i);
}

斐波那契数列
1
2
3
4
5
6
7
8
9
/**
* 斐波那契数列
*/
static int fib(int n){
if(n==1||n==2){
return 1;
}
return fib(n-1)+fib(n-2);
}
最大公约数
1
2
3
4
5
6
7
8
9
10
11
/**
* 最大公约数
*
* 辗转相除法
*/
static int gcd(int m,int n) {
if (n == 0) {
return m;
}
return gcd(n, m % n);
}
用递归改写插入排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 递归关键是找到一种良好的划分方法
* 2.找到地推公式和等价转换
* 对敌
* 对数组的0-倒数第二个元素,这部分排序
* 然后把最后一个元素插入到这个有序的部分中
*/
static void inserSort(int[] arr,int k) {
if (k==0){
return;
}
//对前k-1个元素排序
inserSort(arr,k-1);
//把位置k的元素插入到前面部分
int x = arr[k];
int index = k-1;
while (x<arr[index]){
arr[index+1] = arr[index];
index--;
}
arr[index+1] = x;
}
汉诺塔问题

这个的嘀咕公式有点奇怪:它是文字哦:当只有一个盘子时,直接打印移动路径;
当盘子数量大于 1 时,先将上面 n-1 个盘子从 A 经过 C 移动到 B,然后打印移动第 n 个盘子的路径,最后将 n-1 个盘子从 B 经过 A 移动到 C

  • 汉诺塔问题
    有n个盘子,三个柱子,要把n个盘子按照原石的顺序整体移动到另一个柱子上。而且大盘子不能放在小盘子上,每次只能移动一个盘子。
    N从A移动到B, C作为辅助
    等价于:
    1、N-1移动到C, B为辅助
    2、把N从A移动到B
    3、N从C移动到B, A为辅助
    
  • 思考汉诺塔问题可以先思考两个盘子如何从A移动到C
    1.把第一个盘子先移动到辅助空间B
    2.把第二个盘子移动到to C
    3.把第一个盘子移动到C
1
2
3
4
5
6
7
8
9
10
11
static void printHanoiTower(int N, String from ,String to ,String help){
if(N==1){
System.out.println("move "+ N + " from " + from + " to " + to);
return;
}
//先把压着它的移动到辅助空间
printHanoiTower(N-1,from,help,to);
System.out.println("move "+ N + " from " + from + " to " + to);
//后置操作:让N-1从辅助空间回到原来的源空间
printHanoiTower(N-1,help,to,from);
}

####### 二分查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 二分查找
* 等价于三个子问题
* 1、左边找
* 2、右边找
* 3、中间比
*/
static void binarySearch(int[] arr,int low,int high,int target){
if(low>high){
return;
}
int mid = (low+high)/2;
if(arr[mid]==target){
System.out.println(mid);
return;
}else if(arr[mid]>target){
binarySearch(arr,low,mid-1,target);
}else{
binarySearch(arr,mid+1,high,target);
}
}

常见的算法

希尔排序
  • 比较考验空间思维能力
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* interval步径
* @param arr
*/
static void shellSort2(int[] arr){
//不断地缩小增量
for (int interval = arr.length/2; interval >0 ; interval=interval/2) {
//这里其实是插入排序,把interval换成1就行
// for (int i = 1; i < arr.length; i++) {
// int target = arr[i];
// int j =i-1;
// while(j>-1&&target<arr[j]){
// arr[j+1]= arr[j];
// j--;
// }
// arr[j+1]=target;
// }
//这里是interval步径的插入排序
for (int i = interval; i < arr.length; i++) {
int target = arr[i];
int j =i-interval;
while(j>-1&&target<arr[j]){
arr[j+interval]= arr[j];
j-=interval;
}
arr[j+interval]=target;
}
}
}

常见算法和递归剩下很多的例子由于我还没搞得很清楚,就先留着等日后更新。