写在前面:递归--知道如何处理一个根节点就可以。“以一点处理万点”。这可能是我现在悟到的递归的真谛。(也就是递归三步曲的第三步:单层递归的逻辑)
104. 二叉树的最大深度 (优先掌握递归)
题目
解题要点
视频:二叉树的高度和深度有啥区别?究竟用什么遍历顺序?很多录友搞不懂 | 104.二叉树的最大深度
后序遍历,根节点的高度即是二叉树的最大深度
(也可以用前序遍历,但后序遍历代码简单点)
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
/**后序遍历(左右中) 根节点的高度即是二叉树的最大深度 */
//确定参数和返回值
//确定终止条件
if(root == null) return 0;
int leftheight = maxDepth(root.left); //左
int rightheight = maxDepth(root.right); //右
int height = 1 + Math.max(leftheight, rightheight); //中(左右孩子的最大高度+1返回给父节点)
return height;
}
}
559. n叉树的最大深度
题目
代码
这个是学会了上面二叉树的以后自己写出来的
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public int maxDepth(Node root) {
/**N叉树的最大深度:后序遍历,根节点的高度就是最大深度 */
//1. 确定递归的参数和返回值
//2. 确定递归终止条件
if(root == null) return 0;
//3. 确定单层递归逻辑
int maxheight = 0; //用来存储子节点的最高高度
for(Node child : root.children){
int childheight = maxDepth(child); //每一个子节点的高度
maxheight = Math.max(maxheight, childheight);
}
int height = 1 + maxheight;
return height;
}
}
111. 二叉树的最小深度(优先掌握递归)
题目
解题要点
注意左/右子树其中一个为null另一个不为null的情况,不处理这种情况会返回错误的最小深度。
具体看视频和文字讲解:代码随想录|111.二叉树的最小深度
代码
class Solution {
public int minDepth(TreeNode root) {
/**后序遍历,用高度计算深度,递归 */
//1. 确定递归的参数和返回值
//2. 确定递归终止条件
if(root == null) return 0;
//3.确定单层递归逻辑
int left_minheight = minDepth(root.left); //左
int right_minheight = minDepth(root.right); //右
//中
//int height = Math.min(left_minheight, right_minheight);
//直接取最小值的话未考虑一种情况,就是当前root左/右子树为空时,返回的最小深度不是叶子节点的最小深度而是当前root的深度1.如示例2.
//当左子树为空而右子树不为空时,返回右子树的最小高度+1
if(root.left == null && root.right != null){
return 1 + right_minheight;
}
//当右子树为空而左子树不为空时,返回左子树的最小高度+1
if(root.left != null && root.right == null){
return 1 + left_minheight;
}
//当左右子树都为空或都不为空时,返回左右子树的最小高度的最小值+1(都为空时返回1+ min(0,0))
return 1 + Math.min(left_minheight, right_minheight);
}
}
222.完全二叉树的节点个数
题目
解题要点
可以用普通二叉树去后序遍历返回节点数。但这里是完全二叉树,借助完全二叉树的特性去做性能更优,可以不必像普通二叉树方法那样遍历全部的节点。
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
判断其子树是不是满二叉树,如果是则利用公式计算这个子树(满二叉树)的节点数量,如果不是则继续递归。
因此本题终止条件比一般的后序遍历要多一个:判断子树是否为满二叉树。当子树为满二叉树时,递归终止,返回子树满二叉树的节点数。
视频和文字讲解详见:
代码
class Solution {
public int countNodes(TreeNode root) {
/**利用完全二叉特性 */
/**除底层外, 其他层都是满的。底层从左到右连续*/
/**一定能遍历到左子树是满二叉树,右子树是满二叉树,满二叉树节点数2^k -1, num = 左子满二叉树num + 右子满二叉树num + 1 */
/**后序遍历,递归 */
//1.确定递归的返回值和参数
//2.确定递归终止条件
//终止条件1:当节点为null时
if(root == null) return 0;
//终止条件2: 判断子树是否为满二叉树
TreeNode left = root.left;
TreeNode right = root.right;
int leftdepth = 0; int rightdepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
while(left != null){
left = left.left;
leftdepth ++;
}
while(right != null){
right = right.right;
rightdepth ++;
}
if(leftdepth == rightdepth){
return (2 << leftdepth) - 1; //(左移)位运算,2的深度次方-1
//树的深度k从1开始,而这里leftdepth从0开始,但是位运算 2<<1 = 2^2, 2<<0 = 2^1,因此正好是2<<(leftdepth) -1
//位运算 要用括号括起来
}
//3.确定单层递归逻辑
int leftNotes = countNodes(root.left); //左 (不能直接用left,left变了)
int rightNotes = countNodes(root.right); //右
int result = leftNotes + rightNotes + 1; //中
return result;
}
}
注:这里有个位运算。关于位运算的知识可以参考Java 位运算(移位、位与、或、异或、非)。