本节我们来聊聊树的经典问题——最大深度问题,下面我们就来看看二叉树和N叉树的的深度问题及它们的区别与联系。
首先看一下LeetCode104题最大深度:给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。例如上面的例子返回结果为最大深度为3。
我们先看一个简单情况:
3 3 3 3 / \ / \ / \ 9 20 9 20
对于node(3),最大深度自然是左右子结点+1,左右子节点有的可能为空,只要有一个,树的最大高度就是1+1=2。然后再增加几个结点:
很显然相对于node(20),最大深度自然是左右子结点+1,左右子节点有的可能为空,只要有一个,树的最大高度就是1+1=2,用代码表示就是:
int depth = 1 + max(leftDepth, rightDepth);
(这里的depth的实际意义就是当前节点以下子树的最大深度)
而对于3,则是左右子树深度最大的那个然后再+1,具体谁更大,则不必关心。所以对于node(3)的判断逻辑就是:
int leftDepth = getDepth(node.left); // 左
int rightDepth = getDepth(node.right); // 右
int depth = 1 + max(leftDepth, rightDepth); // 中
那什么时候结束呢,这里仍然是root == null返回0就行了。至于入参,自然是要处理的子树的根节点root,而返回值则是当前root所在子树的最大高度。所以合在一起就是:
public static int maxDepth_1(TreeNode root) {
if (root == null){
return 0;
}
int left = maxDepth_1(root.left);
int right = maxDepth_1(root.right);
return Math.max(left,right) + 1;
}
上面代码先拿到左右子树的结果再计算Math.max(left,right) + 1,这与后序遍历本质上一样的,因此可以看做后序遍历的拓展问题。
我们继续分析这个题,如果确定树最大有几层是不是也就知道最大深度了? 是的,直接套用层序遍历的代码就可以。
具体做法是:我们修改2.2层次遍历中的分层方法,每获得一层增加一下层数就可以了。
public static int maxDepth_2(TreeNode root) {
if (root == null) {
return 0;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
int ans = 0;
while (!queue.isEmpty()) {
//size表示某一层的所有元素数
int size = queue.size();
//size=0 表示一层访问完了
while (size > 0) {
TreeNode node = queue.poll();
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
size--;
}
ans++;
}
return ans;
}
如果将二叉树换成N叉树又该怎么做呢?这就是LeetCode559.给定一个 N 叉树,找到其最大深度。最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。
示例1:
输入:root = [1,null,3,2,4,null,5,6]
输出:3
示例2:
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:5
这道题就是将二叉树换成了N叉树,不同点就在于N叉树结点比较多,我们使用List存,遍历时用for即可,我们先看N叉树的定义:
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;
}
}
这个题的实现和上一个题的最大区别就是处理子树时加了个处理List的for循环
public static int maxDepth_N(NTreeNode root) {
if (root == null) {
return 0;
}
if (root.children == null || root.children.isEmpty()) {
return 1;
}
LinkedList<Integer> height = new LinkedList<>();
for (NTreeNode chd : root.children) {
height.offer(maxDepth_N(chd));
}
return Collections.max(height) + 1;
}
本题也可以使用层序遍历的方法进行求解,相比二叉树,这里对应每个节点的children是否为null,对于children中的元素是否为null,要考虑周全,这也是该方法符难点。(不会有人被空指针异常卡了2小时吧)
解答如下:
public static int maxDepth_N1(NTreeNode root) {
if (root == null)
return 0;
int N_depth = 0;
Queue<NTreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
NTreeNode t = queue.poll();
if (t.children != null) {
for (NTreeNode chd : t.children) {
if (chd != null)
queue.add(chd);
}
}
}
N_depth++;
}
return N_depth;
}