今日内容:
● 104.二叉树的最大深度 559.n叉树的最大深度
● 111.二叉树的最小深度
● 222.完全二叉树的节点个数
迭代法,大家可以直接过,二刷有精力的时候 再去掌握迭代法。
1. 二叉树的最大深度 (优先掌握递归)
关联 leetcode 104.二叉树的最大深度
-
定义
- 叶子节点:
- 没有子节点的节点
- 深度:
- 【把根节点看作地表,下面的节点都是深埋的树根,每一层树根埋的深度】
- 任意一个节点到根节点的距离
- 自身节点算一个度,第二层节点的深度是 2
- 根节点的深度是1
- 求解方式:
- 从上往下计数
- 从根节点往下走到目标节点
- 根节点初始深度:1,往下走一次 +1
- 前序遍历
- 从上往下计数
- 高度:
- 【把二叉树反过来看,叶子节点代表树冠,整棵树的高度】
- 二叉树中任意一个节点到叶子节点的距离
- 假设有一颗3层满二叉树,
- 根节点的高度:3
- 第二层节点的高度:2
- 叶子节点高度:1
- 假设有一颗3层满二叉树,
- 求解方式
- 从下往上计数
- 从叶子节点往上走到目标节点
- 父节点知道子节点【例如叶子节点的高度】+本层的 高度1 就行
- 后序遍历
- 从下往上计数
- 叶子节点:
-
题解
- 最大深度 == 根节点的高度
func getHeight(node *TreeNode) int { if node == nil { return 0 } // 左孩子高度 leftHeight := getHeight(node.Left) // 右孩子高度 rightHeight := getHeight(node.Right) // 当前节点高度 height := 1 + max(leftHeight, rightHeight) return height } func maxDepth(root *TreeNode) int { return getHeight(root) }
2. 二叉树的最小深度 (优先掌握递归)
关联 leetcode 111.二叉树的最小深度
- 二叉树的最小深度
- 最小深度是从根节点到最近叶子节点的最短路径上的节点数量
- 叶子节点:左右孩子都为空
- 最小深度是从根节点到最近叶子节点的最短路径上的节点数量
- 补充定义
- 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
- 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数后者节点数(取决于高度从0开始还是从1开始)
- 题解
-
使用后序遍历
- 其实求的是根节点到叶子节点的最小距离,就是求高度的过程,不过这个最小距离 也同样是最小深度
-
递归
func getDepth(node *TreeNode) int { if node == nil { return 0 } leftDepth := getDepth(node.Left) rightDepth := getDepth(node.Right) if node.Left == nil && node.Right != nil { return 1 + rightDepth } if node.Right == nil && node.Left != nil { return 1 + leftDepth } depth := 1 + min(leftDepth, rightDepth) return depth } func minDepth(root *TreeNode) int { return getDepth(root) }
-
2. 完全二叉树的节点个数(优先掌握递归)
关联 leetcode 222.完全二叉树的节点个数
- 统计节点数量
-
普通二叉树
-
所有处理节点都是当前遍历到的节点【可以抽象的看作都是中间节点】
-
递归
//闭包实现 func countNodes(root *TreeNode) int { if root == nil { return 0 } res := 0 var loopNode func(node *TreeNode) int loopNode = func(node *TreeNode) int { if node == nil { return 0 } //前序遍历, 中后序同理 res += 1 loopNode(node.Left) loopNode(node.Right) return res } loopNode(root) return res } // 实现2 func countNodes(root *TreeNode) int { if root == nil { return 0 } var loopNode func(node *TreeNode) int loopNode = func(node *TreeNode) int { if node == nil { return 0 } //前序遍历, 中后序同理 leftSonSum := loopNode(node.Left) rightSonSum := loopNode(node.Right) nodesSum := 1 + leftSonSum + rightSonSum //当前节点+左右子树的节点数量 return nodesSum } return loopNode(root) }
-
层序遍历
func countNodes(root *TreeNode) int { if root == nil { return 0 } res := 0 nodes := make([]*TreeNode, 0) nodes = append(nodes, root) for len(nodes) > 0 { node := nodes[len(nodes)-1] if node != nil { res += 1 } nodes = nodes[:len(nodes)-1] if node.Left != nil { nodes = append(nodes, node.Left) } if node.Right != nil { nodes = append(nodes, node.Right) } } return res }
-
-
完全二叉树
- 除了底层节点,上面的每层都是满节点
- 底层节点从左到右依次填满
-
- 题解
-
普通二叉树做法
-
递归
//闭包实现 func countNodes(root *TreeNode) int { if root == nil { return 0 } res := 0 var loopNode func(node *TreeNode) int loopNode = func(node *TreeNode) int { if node == nil { return 0 } //前序遍历, 中后序同理 res += 1 loopNode(node.Left) loopNode(node.Right) return res } loopNode(root) return res } // 实现2 func countNodes(root *TreeNode) int { if root == nil { return 0 } var loopNode func(node *TreeNode) int loopNode = func(node *TreeNode) int { if node == nil { return 0 } //前序遍历, 中后序同理 leftSonSum := loopNode(node.Left) rightSonSum := loopNode(node.Right) nodesSum := 1 + leftSonSum + rightSonSum //当前节点+左右子树的节点数量 return nodesSum } return loopNode(root) }
-
层序遍历
func countNodes(root *TreeNode) int { if root == nil { return 0 } res := 0 nodes := make([]*TreeNode, 0) nodes = append(nodes, root) for len(nodes) > 0 { node := nodes[len(nodes)-1] if node != nil { res += 1 } nodes = nodes[:len(nodes)-1] if node.Left != nil { nodes = append(nodes, node.Left) } if node.Right != nil { nodes = append(nodes, node.Right) } } return res }
-
-
完全二叉树做法
- 如果左右子树分别向左右遍历的得到的深度一致
- 子树的外侧长度一致
- 从该节点往下到叶子节点是一棵满二叉树
- 节点数量:
- 2^depth-1
- 节点数量:
-
题解
func countNodes(root *TreeNode) int { if root == nil { return 0 } leftSon := root.Left rightSon := root.Right leftDepth, rightDepth := 0, 0 for leftSon != nil { leftSon = leftSon.Left leftDepth++ } for rightSon != nil { rightSon = rightSon.Right rightDepth++ } //整棵树是满二叉树 if leftDepth == rightDepth { return (2 << leftDepth) - 1 // 注意(2<<1) 相当于2^2,所以leftDepth初始为0 } //这个棵树不是满二叉树: 计算 根节点+左子树节点数+右子树节点数 return 1 + countNodes(root.Left) + countNodes(root.Right) }
- 如果左右子树分别向左右遍历的得到的深度一致
-