剑指offer | 面试题41:二叉树的深度_剑指offer


欢迎关注千羽的公众号

剑指offer | 面试题41:二叉树的深度_子树_02

Leetcode : https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/


GitHub :  https://github.com/nateshao/leetcode/blob/main/algo-notes/src/main/java/com/nateshao/sword_offer/topic_41_maxDepth/Solution.java


剑指 Offer 55 - I. 二叉树的深度

题目描述 :输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。

难度:简单


例如:给定二叉树 [3,9,20,null,null,15,7],

3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。

方法一:递归 (后序遍历)

树的遍历方式总体分为两类:深度优先搜索(DFS)、广度优先搜索(BFS);


  • 常见的 DFS : 先序遍历、中序遍历、后序遍历(左右根);
  • 常见的 BFS : 层序遍历(即按层遍历)。



  • 树的后序遍历 / 深度优先搜索往往利用 递归 实现
  • 关键点: 此树的深度和其左(右)子树的深度之间的关系。显然,此树的深度 等于 左子树的深度右子树的深度 中的 最大值 +1 。

剑指offer | 面试题41:二叉树的深度_二叉树_03

算法解析:
  1. 终止条件: 当 ​​root​​ 为空,说明已越过叶节点,因此返回 深度 0 。
  2. 递推工作:本质上是对树做后序遍历。

  1. 计算节点 root 的 左子树的深度 ,即调用 maxDepth(root.left);
  2. 计算节点 root 的 右子树的深度 ,即调用 maxDepth(root.right);

  1. 返回值: 返回 此树的深度 ,即 ​​max(maxDepth(root.left), maxDepth(root.right)) + 1​​。

剑指offer | 面试题41:二叉树的深度_二叉树_04

  1. In other words, 考虑以下几种情况:
    如果二叉树为空,深度为 0;如果二叉树只有根节点,深度为 1;如果二叉树的根节点只有左子树,深度为左子树的深度加 1;如果二叉树的根节点只有右子树,深度为右子树的深度加 1;如果二叉树的根节点既有左子树又有右子树,深度为左右子树深度的最大者再加 1。
复杂度分析:

  • 时间复杂度 O(N):N 为树的节点数量,计算树的深度需要遍历所有节点。
  • 空间复杂度 O(N) :最差情况下(当树退化为链表时),递归深度可达到 N  。

package com.nateshao.one_question_per_day.code_2022.january;

/**
* @date Created by 邵桐杰 on 2022/1/22 22:56
* @微信公众号 千羽的编程时光
* @个人网站 www.nateshao.cn
* @博客 https://nateshao.gitee.io
* @GitHub https://github.com/nateshao
* @Gitee https://gitee.com/nateshao
* Description:
*/
public class Solution_2022_01_22_maxDepth {

/**
* 方法一:递归解法
* 思路:利用递归遍历分别返回左右子树深度
*
* @param root
* @return
*/
public int maxDepth(TreeNode root) {
// return root == null ? 0 : Math.max(maxDepth(root.left), maxDepth(root.right) + 1);
if (root == null) return 0;
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return Math.max(left, right) + 1;
}

public class TreeNode {
int val;

TreeNode left;
TreeNode right;

TreeNode(int x) {
val = x;
}
}
}

Golang

/* go 语言没有三目运算符 */
func maxDepth(root *TreeNode) int {
if root == nil {
return 0
}
return max(maxDepth(root.Left), maxDepth(root.Right)) + 1
}

func max(a, b int) int {
if a > b {
return a
}
return b
}

方法二:非递归一一层序遍历(BFS)


  • 树的层序遍历 / 广度优先搜索往往利用 队列 实现。
  • 关键点: 每遍历一层,则计数器 +1 ,直到遍历完成,则可得到树的深度。

算法解析:
  1. 特例处理: 当 ​​root​​ 为空,直接返回 深度 0 。
  2. 初始化: 队列 ​​queue​​​ (加入根节点 ​​root​​​ ),计数器 ​​res = 0​​。
  3. 循环遍历: 当 ​​queue​​ 为空时跳出。

  1. 初始化一个空列表 ​​tmp​​ ,用于临时存储下一层节点;
  2. 遍历队列:遍历 ​​queue​​​ 中的各节点 ​​node​​​ ,并将其左子节点和右子节点加入 ​​tmp​​;
  3. 更新队列:执行 ​​queue = tmp​​​ ,将下一层节点赋值给 ​​queue​​;
  4. 统计层数:执行 ​​res += 1​​ ,代表层数加 1;

剑指offer | 面试题41:二叉树的深度_剑指offer_05

/**
* 方法二:层序遍历(BFS)
* @param root
* @return
*/
public int maxDepth2(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
int res = 0;
while (!queue.isEmpty()) {
res++;
int n = queue.size();
for (int i = 0; i < n; i++) {
TreeNode node = queue.poll();
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
}
return res;
}

Golang

/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func maxDepth(root *TreeNode) int {
// 边界
if root == nil {
return 0
}
depth := 0
var queue []*TreeNode
queue = append(queue, root)
// bfs
for len(queue) > 0 {
length := len(queue)
for i := 0; i < length; i++ {
cur := queue[0]
queue = queue[1:]
if cur.Left != nil {
queue = append(queue, cur.Left)
}
if cur.Right != nil {
queue = append(queue, cur.Right)
}
}
depth += 1
}
return depth
}

参考链接:


  1. ​https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/solution/mian-shi-ti-55-i-er-cha-shu-de-shen-du-xian-xu-bia/​
  2. ​https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/solution/jian-zhi-offer-55-i-er-cha-shu-de-shen-du-di-gui-c/​


END


革命尚未成功,同志仍需努力,冲冲冲