递归其实特别简单,你只需要知道两件事
一:递归什么时候停止?也就是你一眼就能看到结果的时候
二:递归的表达式是什么?就是你能通过前面的结果,得知后面的结果
- 最重要的事情,千万不要试图追踪递归执行的过程,计算机不会出错,你只要明白前面的两个条件,任何递归都能搞明白,只想有一两个成员的情况就好,要不然约绕越闷。
阶乘
private static int factorial(int n) {
//结束条件 1的阶乘 我们都知道
if (n == 1) {
return 1;
}
//表达式 3的阶乘 是不是3乘以2的阶乘
//那么OK n的阶乘 就是 n乘 n-1的阶乘
return (n * factorial(n-1));
}
斐波那契数列
1、1、2、3、5、8、13
private static int fibonacci(int n) {
//结束条件 n=1 时候 那肯定是1 n=2时候 也是1
if (n == 1 || n == 2) {
return 1;
}
//递归表达式 某一项的值 是前两项的和 那么OK
return fibonacci(n-1) + fibonacci(n-2);
}
跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法
public int JumpFloor(int target) {
//结束条件 如果是1级 那么一种方法 如果是2级 那么2种方法
if(target <= 2) {
return target;
} else {
//表达式 到目标共有2种方法 要么从target-1跳一级上去 要么从target-2跳两级上去
//两者或的关系 相加
return JumpFloor(target-1) + JumpFloor(target-2);
}
}
二叉树最大深度
public int maxDepth(TreeNode root) {
//结束条件 一个节点没有 那肯定是0
if(null == root) {
return 0;
}
//表达式 分别将左右子树看作新的树 求左右子树的最大值
// +1 加当前
return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
}
汉诺塔
private static void hanoi(int n, char start, char transfer, char target) {
//结束条件 只有一个盘子,二话不说 扔到目标柱子 完事
if (n == 1) {
System.out.println(start + "---->" + target);
} else {
// 表达式 柱子上有两个盘子 一个大盘子 n
// 另外一个小盘子(n-1是一个整体)
// 那么很简单 把小盘子扔到辅助 然后就可以把大盘子扔到目标了
// 起始柱子借助目标柱子将盘子扔到辅助柱子
hanoi(n - 1, start, target, transfer);
System.out.println(start + "---->" + target);
//辅助柱子上的盘子同上面一样的道理 借助起始 扔到目标
hanoi(n - 1, transfer, start, target);
}
}
机器人运动范围
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
public int movingCount(int threshold, int rows, int cols){
boolean[][] flag = new boolean[rows][cols];
return calculate(threshold, rows, cols, 0, 0, flag);
}
private static int calculate(int threshold, int rows, int cols,
int i, int j, boolean[][] flag) {
//结束条件 当越界 或者已经访问过的时候 那么就是不能进入 直接返回0
if (i >= rows || i < 0 || j >= cols || j < 0 || flag[i][j]) {
return 0;
}
//行列坐标和符合范围
if (i/10 + i%10 + j/10 + j%10 <= threshold) {
flag[i][j] = true;
//表达式 所有格子都一样 如同访问第一个格子一样 return calculate(threshold, rows, cols, 0, 0, flag);
//访问4个邻居格子即可
return calculate(threshold, rows, cols, i - 1, j, flag)
+ calculate(threshold, rows, cols, i + 1, j, flag)
+ calculate(threshold, rows, cols, i, j - 1, flag)
+ calculate(threshold, rows, cols, i, j + 1, flag)
+ 1;
} else {
return 0;
}
}
矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
public boolean hasPath(char[] array, int rows, int cols, char[] str) {
if (rows == 0 || cols == 0) {
return false;
}
boolean[][] marked = new boolean[rows][cols];
char[][] matrix = buildMatrix(array, rows, cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
//如果backtracking返回ture 那么存在 否则继续从探下一个点
if (backtracking(matrix, str, rows, cols, marked, 0, i, j)) {
return true;
}
}
}
//全部找完,backtracking没找到 不存在
return false;
}
private boolean backtracking(char[][] matrix, char[] str, int rows, int cols,
boolean[][] marked, int pathLen, int r, int c) {
if (pathLen == str.length) {
return true;
}
if (r < 0 || r >= rows || c < 0 || c >= cols
|| matrix[r][c] != str[pathLen] || marked[r][c]) {
//matrix[r][c] != str[pathLen] 该字符与要找的不一样
//marked[r][c] 已经标记过来了 不能重复
return false;
}
//找到了某个字符
marked[r][c] = true;
//遍历它的上下左右
if (backtracking(matrix, str, rows, cols, marked, pathLen+1, r+1, c )
|| backtracking(matrix, str, rows, cols, marked, pathLen+1, r-1, c)
|| backtracking(matrix, str, rows, cols, marked, pathLen+1, r, c-1)
|| backtracking(matrix, str, rows, cols, marked, pathLen+1, r, c+1)) {
return true;
}
//它的上下左右没有路径,那么找到的单个字符没有用,置为false
marked[r][c] = false;
return false;
}
private char[][] buildMatrix(char[] array, int rows, int cols) {
char[][] matrix = new char[rows][cols];
for (int r = 0, idx = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
matrix[r][c] = array[idx++];
}
}
return matrix;
}