学习目标:
掌握递归
学习内容:
- 递归相关例题
递归:
递归是一种解决计算问题的方法,其中解决方案取决于同一类问题的更小子集。
翻译翻译:
深入到最里层叫递,
从最里层出来叫归。
说明:
1.自己调用自己,即解决方案是一样的
2.每次调用,函数处理的数据会较上次缩减
3.内层函数调用完成,外层函数才能调用完成
例1:求阶乘
public static int f(int n) {
if (n == 1) return 1;
return n * f(n - 1);
}
例2:反向打印字符串
public static void f(int n,String str){
if(n==str.length()){
return;
}
f(n+1,str);
System.out.println(str.charAt(n));
}
例3:递归二分查找
//递归二分查找
public static int f(int[] a, int target, int low, int high) {
if (low > high) { //没找到
return -1;
}
int mid = (low + high) >>> 1;
if (target < a[mid]) {
return f(a, target, low, mid - 1);
} else if (target > a[mid]) {
return f(a, target, mid + 1, high);
} else return mid;
}
例4: 递归冒泡排序
public static void bubble(int[] a, int j) {
if (j == 0) return;
int x = 0;//每次交换时x=i,排序一遍后x的右边元素都已经排序好,下一趟以x为上界即可
for (int i = 0; i < j; i++) {
if (a[i] > a[i + 1]) {
int t = a[i];
a[i] = a[i + 1];
a[i + 1] = t;
x = i;
}
}
bubble(a, x);
}
例5:递归插入排序
public static void insertion(int[] a, int low) {
if (low == a.length) {
return;
}
int t = a[low];
int i = low - 1; //已排序区域的指针
while (i >= 0 && a[i] > t) { //没有找到排序位置
a[i + 1] = a[i]; //空出插入位置
i--;
}
//找到插入位置
a[i + 1] = t;
insertion(a, low + 1);
}
例6:斐波那契数列
原始递归版:
public static int f(int n){
if(n==0)return 0;
if(n==1)return 1;
return f(n-1)+f(n-2);
}
备忘录法改进:
思路是用一个数组存储已经计算过的f(n)对应的值,当再次需要计算f(n)时可以直接根据索引查询。
//斐波那契数列-备忘录版
public static int f(int n, int[] cache) {
if(cache[n] != -1){
return cache[n];
}
int x = f(n-1,cache);
int y = f(n-2,cache);
cache[n] = x+y;
return cache[n];
}
public static int fibonacci(int n) {
int[] cache = new int[n + 1];
Arrays.fill(cache, -1); //初始值为-1,便于判断是否存储过
cache[0] = 0;
cache[1] = 1;
return f(n,cache);
}
多路递归:
例1:汉诺塔
public class HanoiTower {
static LinkedList<Integer> a = new LinkedList<>();
static LinkedList<Integer> b = new LinkedList<>();
static LinkedList<Integer> c = new LinkedList<>();
//初始化
static void init(int n){
for (int i = 0; i < n; i++) {
a.addLast(i);
}
}
static void move(int n,LinkedList<Integer> a,
LinkedList<Integer> b,
LinkedList<Integer> c){
if(n==0)return;
move(n-1,a,c,b);
c.addLast(a.removeLast());
move(n-1,b,a,c);
}
public static void main(String[] args) {
init(3);
print();
move(3,a,b,c);
System.out.println("-----------");
print();
}
//打印汉诺塔
private static void print() {
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
}
例2:递归杨辉三角
public class PascalTriangle {
private static int element(int i, int j) {
if (j == 0 || i == j) return 1;
return element(i - 1, j - 1) + element(i - 1, j);
}
public static void print(int n) {
for (int i = 0; i < n; i++) {
for (int j = 0; j <= i; j++) {
System.out.print(element(i, j));
}
System.out.println();
}
}
public static void main(String[] args) {
print(4);
}
}
也可以考虑采用数组记忆法,利用空间换取时间从而优化