树的面试题解法一般都是递归,因为
- 结点的定义就是以递归方式进行
- 重复性(自相似性)
二叉搜索树:左子树小于根节点,右子树大于根节点,且左右子树具有相同特征
1 递归( recursion)
本质类似于循环,通过循环体进行
现实生活中的重复性
电影盗梦空间:
- 向下进入不同的梦境,向上回到原来的一层
- 通过声音同步回到上一层
- 每一层的内容都是一份拷贝,主角(参数)进入不同层次梦境(发生并携带变化)后,再一层层返回
1.1 简单的递归
1.2 递归的代码模板
python
java
1.3 思维要点
- 不要进行人肉递归(不画递归的状态树)
- 找到最近最简单的方法,拆解成可重复解决的问题(最近重复子问题)
- 数学归纳法思维(最开始的条件成立,证明n成立n+1也能成立)
2 算法题解
1)22. 括号生成
- [22] 括号生成
- 通过递归的方式,类似于树
- 记录left括号和right括号的个数
- left保持继续添加,right在小于left的时候添加并继续调用函数
- 这样会形成满足条件的树状结构
- 参数left right string res 都是携带改变状态进行传递的
import java.util.ArrayList;
/*
* @lc app=leetcode.cn id=22 lang=java
*
*
*/
// @lc code=start
class Solution {
public List<String> generateParenthesis(int n) {
List<String> res = new ArrayList<>();
generate(0, 0, n, "", res);
return res;
}
public void generate(int left, int right, int n, String string, List<String> res){
if (left == n && right == n) {
res.add(string);
return;
}
if (left < n) generate(left+1, right, n, string+"(", res);
if (right < left) generate(left, right+1, n, string+")", res);
}
}
// @lc code=end
2)[236] 二叉树的最近公共祖先
import org.graalvm.compiler.debug.CSVUtil.Escape;
import jdk.nashorn.api.tree.BinaryTree;
/*
* @lc app=leetcode.cn id=236 lang=java
*
* [236] 二叉树的最近公共祖先
*/
// @lc code=start
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// 终止条件:找到返回root, 直到 没有子树也找不到就返回null(root.left/right == null)
// 由上一层的 left/right 接收这层的返回值
if (root == null) return null;
if (root == p || root == q) return root;
// 循环体:递归左右子树
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
// 判断条件:首先注意层级顺序
// 左子树找不到,就在右子树找
if (left == null) return right;
// 此时右子树没有q/p,就在左子树找q/p
else if (right == null) return left;
//root.left 和 root.right两个子树都有,那就返回这两个子树的根root
else return root;
}
}
// @lc code=end
图解