赞
踩
递归:自己调用自己。本质就是找到前后的联系,找到递归的公式。
回溯:执行一次深度优先遍历(DFS),一条路走到底,走不通的时候,返回回来,继续执行,一直这样下去,直到回到起点。
一般情况为:
if (终止条件) {
return;
}
recursion(参数1);
阶乘
public int recursion(int n) {
//终止条件
if (n == 1)
return 1;
//调用自己
return n * recursion(n - 1);
}
递归过程:
求f(5)的时候,只需要求出f(4)即可,如果求f(4)我们要求出f(3)……,一层一层的调用,当n=1的时候,我们直接返回1,然后再一层一层的返回,直到返回f(5)为止。
一些较实际的情况:
if (终止条件) {
return;
}
可能有一些逻辑运算
recursion(参数1);
可能有一些逻辑运算
recursion(参数2);
……
recursion(参数n);
可能有一些逻辑运算
反转链表
public static void reverseList(ListNode root) {
//(终止条件)
if (root == null)
return ;
//(递归调用)先打印下一个
reverseList(root.next);
//(逻辑处理)把后面的都打印完了在打印当前节点
System.out.print(root.val + " ");
}
结果如下:
回溯的本质,其实是在递归基础上进行了改进
一般情况为:
if(不满足继续递归查找的条件,通常为界限判断)
return;
if(满足查找条件)
return 这个值/节点;
递归左边
递归右边
递归结果判断-回溯
判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。
示例:
输入:board = [
["a","b"],
["c","d"]
],
word = "abcd"
输出:false
class Solution { public boolean exist(char[][] board, String word) { char[] words = word.toCharArray(); for(int i = 0; i < board.length; i++) { for(int j = 0; j < board[0].length; j++) { if(dfs(board, words, i, j, 0)) return true; } } return false; } //回溯 boolean dfs(char[][] board, char[] word, int i, int j, int k) { //边界条件(越界、与目标元素不同) if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false; //全部匹配完成 if(k == word.length - 1) return true; char temp = board[i][j]; board[i][j] = '\0';//将当前元素标记为'\0',不可再被访问 //递归上下左右 boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) ||dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1); board[i][j] = temp;//恢复其本身值 //递归结果判断-回溯 return res;//上面4个方向,只要有一个能查找到,就返回true } }
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUXcdhJx-1605416128009)(</images/OFfer68.PNG>)]
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
思想:通过递归对二叉树进行后序遍历,当遇到节点 p 或 q 时返回。从底至顶回溯,当节点 p, q 在节点 root 的异侧时,节点root 即为最近公共祖先,则向上返回 root 。
p,q和root有三种情况:
1). p,q在root左右,返回root
2). p,q都在root左,返回lowestCommonAncestor( root.left, TreeNode p, TreeNode q)
3). p,q都在root右,返回lowestCommonAncestor( root.right, TreeNode p, TreeNode q)
递归终止条件
if(root == null) return null;//越过叶子节点,返回null
if(root == p) return p;//找到p,返回p
if(root == q) return q;//找到q,返回q
递归体
递归左子节点,返回值为left
TreeNode left = lowestCommonAncestor( root.left, TreeNode p, TreeNode q);
递归右子节点,返回值为right
TreeNode right = lowestCommonAncestor( root.right, TreeNode p, TreeNode q);
递归结果
1).left == null && right == null
两边都没找到,返回null
2).left == null
右边找到,返回right
3). right == null
右边找到,返回left
4).left != null && right != null
说明p,q在root两侧,返回root
图文过程详解
代码实现
class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { //终止条件 if(root == null || root == p || root == q) return root; //递归体 TreeNode left = lowestCommonAncestor( root.left, p, q); TreeNode right = lowestCommonAncestor( root.right, p, q); //递归结果判断-回溯 if(left == null && right == null) return null; if(left == null) return right; if(right == null) return left; return root; } }
算法小白对递归和回溯的理解只到这里,希望随着刷的题越来越多,理解也越来越清晰透彻,到时再来分享!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。