递归:
-
注意当前节点做的事如何利用返回值 – 思考用什么类型的返回值,怎么操作返回值?
因此,返回值的类型也可以确定了。 -
注意是否要利用其他private函数,如果用,那么private函数的输入参数和返回值是什么。
-
要求树的整体的某个值,比如树的直径,树是否是平衡的,应该定义一个全局变量。
- 树的深度/高度(数得是边数,不是节点数)
public int maxDepth(TreeNode root){
if (root == null) return 0;
int l = maxDepth(roo.left);
int r = maxDepth(root.right);
return Math.max(l, r) + 1;
}
- 判断平衡树(利用1:树的深度/高度)
private boolean result = true;
public boolean isBalanced(TreeNode root){
maxDepth(root);
return result;
}
private int maxDepth(TreeNode root){
if (root == null) return 0;
int l = maxDepth(root.left);
int r = maxDepth(root.right);
if (Math.abs(l - r) > 1) result = false;
return Math.max(l, r) + 1;
}
- 树的直径(数得边数,正好利用1:树的深度/高度)
private int max = 0;
public int diameterOfTree(TreeNode root) {
maxDepth(root);
return max;
}
private int maxDepth(TreeNode root){
if (root == null) return 0;
int l = maxDepth(roo.left);
int r = maxDepth(root.right);
max = Math.max(max, l+r);
return Math.max(l, r) + 1;
}
- 翻转树
public TreeNode invertTree(TreeNode root){
if (root == null) return null;
TreeNode left = root.left;
root.left = invertTree(root.right);
root.right = invertTree(left);
return root;
}
- 合并树
public TreeNode mergeTrees(TreeNode t1, TreeNode t2){
//停止条件:
if (t1 == null && t2 == null) return null;
if (t1 == null) return t2;
if (t2 == null) return t1;
//当前节点操作:
TreeNode root = new TreeNode(t1.val + t2.val); //新建节点
//交给递归:
root.left = mergeTrees(t1.left, t2.left);
root.right = mergeTrees(t1.right, t2.right);
//返回:
return root;
}
- 是否有路径和(路径和定义为从 root 到 leaf 的所有节点的和)== targetSum
public boolean pathSum(TreeNode root, int targetSum) {
if (root == null) return false;
if (root.left == null && root.right == null && root.val == sum) return true;
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
- 路径和(路径不一定以 root 开头,也不一定以 leaf 结尾,但是必须连续)== targetSum 的数量
第一重递归:遍历树的每一个节点。
第二重递归:计算从每一个节点出发一共能有多少条路径。
//遍历树的每一个节点(以当前节点为root,以root.left为root, 以root.right为root),把返回的ret(路径和=targetSum数)加起来
public int pathSum(TreeNode root, int sum) {
if (root == null) return 0;
int ret = pathSumWithRoot(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
return ret;
}
//返回以每一个节点为root的路径数
private int pathSumWithRoot(TreeNode root, int sum) {
if (root == null) return 0;
int ret = 0;
if (root.val == sum) ret++;
ret += pathSumWithRoot(root.left, sum - root.val) + pathSumWithRoot(root.right, sum - root.val);
return ret;
}
- 判断 树t 是否是 另一棵树s 的子树
双层递归函数,递归函数又套了另一个递归函数。外面的递归函数用于遍历每一个节点(输入当前节点root,操作root,root.left, root.right);内层递归函数作用于当前节点,根据题意进行设计,是主要“做事”的函数。
第一重递归:遍历树的每一个节点。
第二重递归:判断以当前节点为root的树是不是t这个子树。
//遍历树的每一个节点(以当前节点为root,以root.left为root, 以root.right为root),判断树t是否是s的子树
public boolean isSubtree(TreeNode root, TreeNode t) {
if (root == null) return false;
return isSubtreeWithRoot(root, t) || isSubtree(root.left, t) || isSubtree(root.right, t);
}
//判断以当前节点为root的树是不是t这个子树
private boolean isSubtreeWithRoot(TreeNode root, TreeNode t) {
if (root == null && t == null) return true;
if (root == null || t == null) return false;
return root.val == t.val && isSubtreeWithRoot(root.left, t.left) && isSubtreeWithRoot(root.right, t.right);
}
- 判断树是否symmetric
判断对称的标准:
左右节点值要相同
左节点的左子和右节点的右子要对称,右节点的左子和左节点的右子要对称。
//判断root的左右节点是否对称,调用isSymmetric(root.left, root.right)
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return isSymmetric(root.left, root.right);
}
//判断对称的递归函数:判断当前节点的左右节点是不是对称的,若要对称,则要满足:节点值相同;左节点的左子和右节点的右子对称 && 左节点的右子和右节点的左子对称
private boolean isSymmetric(TreeNode left, TreeNode right) {
if (left == null && right == null) return true;
if (left == null || right == null) return false;
return left.val == right.val && isSymmetric(left.left, right.right) && isSymmetric(left.right, right.left);
}
- 最小路径(数的是节点数量,从root到leaf的最短距离)
和maxDepth不同,minDepth不能只写Math.min(l, r) + 1。
public int minDepth(TreeNode root) {
if (root == null) return 0;
int l = minDepth(root.left);
int r = minDepth(root.right);
//若一边有距离,一边没距离,那最短距离就是有距离的那边的距离+1
if (l == 0 || r == 0) return l + r + 1;
//若两边都有距离,选近的距离那边,+1
return Math.min(l, r) + 1;
}
- 左叶子之和
当前节点操作:
如果当前节点的左子是leaf node,那么左子val + 右子树递归;
如果当前节点的左右子都不是leaf node,那么左右子树分别递归,求和。
public int sumOfLeftLeaves(TreeNode root) {
//别忘了corner case:null
if (root == null) return 0;
//如果当前节点的左子是leaf node,那么左子val + 右子树递归
if (isLeaf(root.left)) return root.left.val + sumOfLeftLeaves(root.right);
//如果当前节点的左右子都不是leaf node,那么左右子树分别递归,求和
return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
}
//判断当前节点是否是leaf node
private boolean isLeaf(TreeNode root) {
//corner case:null
if (root == null) return false;
//要满足左右子都是null才是leaf node
return root.left == null && root.right == null;
}