leetcode
leetcode 851 ~ 900
二叉树的完全性检验

二叉树的完全性检验

难度:

标签:

题目描述

给你一棵二叉树的根节点 root ,请你判断这棵树是否是一棵 完全二叉树 。

在一棵 完全二叉树 中,除了最后一层外,所有层都被完全填满,并且最后一层中的所有节点都尽可能靠左。最后一层(第 h 层)中可以包含 1 到 2h 个节点。

 

示例 1:

输入:root = [1,2,3,4,5,6]
输出:true
解释:最后一层前的每一层都是满的(即,节点值为 {1} 和 {2,3} 的两层),且最后一层中的所有节点({4,5,6})尽可能靠左。

示例 2:

输入:root = [1,2,3,4,5,null,7]
输出:false
解释:值为 7 的节点不满足条件「节点尽可能靠左」。

 

提示:

  • 树中节点数目在范围 [1, 100]
  • 1 <= Node.val <= 1000

代码结果

运行时间: 19 ms, 内存: 16.1 MB


// 使用Java Stream的方式实现完全二叉树的判断
// 思路:同样使用广度优先搜索,并利用Java Stream处理节点的队列

import java.util.*;
import java.util.stream.*;

public class Solution {
    public boolean isCompleteTree(TreeNode root) {
        if (root == null) return true;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        boolean end = false;
        while (!queue.isEmpty()) {
            List<TreeNode> level = queue.stream().collect(Collectors.toList());
            queue.clear();
            for (TreeNode node : level) {
                if (node == null) {
                    end = true;
                } else {
                    if (end) return false;
                    queue.offer(node.left);
                    queue.offer(node.right);
                }
            }
        }
        return true;
    }
}

// TreeNode类的定义:
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

解释

方法:

该题解使用广度优先搜索的方式遍历二叉树。它使用一个双端队列来保存每一层的节点。在遍历过程中,如果当前节点的左右子节点都存在,则将其加入到下一层的队列中。如果遇到一个节点只有左子节点或者没有子节点,则将标记置为True,表示后续节点都必须是叶子节点。如果后续遇到非叶子节点,则说明该二叉树不是完全二叉树。在遍历的同时记录下最大深度和第一次遇到叶子节点时的深度,最后根据这两个深度判断是否为完全二叉树。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在广度优先搜索中,如何确保所有层除最后一层外都被完全填满?
在广度优先搜索(BFS)中,每一层的节点都是依次从队列中取出,并将其子节点按照从左到右的顺序加入队列中。通过这种方法,只要一个节点有子节点,这些子节点就会被添加到队列中,从而保证除最后一层外的每一层都被完全填满。如果在某一层中发现节点不符合完全二叉树的子节点存在规则(如只有右子节点,没有左子节点),则可以立即判断该二叉树不是完全二叉树。
🦆
当发现一个节点只有右子节点而没有左子节点时直接返回False,是基于什么完全二叉树的性质?
完全二叉树的性质要求,除了最后一层外,每一层必须是完全填满的,并且最后一层的节点都尽可能地向左对齐。因此,如果在某个节点处发现它只有右子节点而没有左子节点,这违反了节点必须从左到右连续存在的规则,因此可以立即判断该二叉树不是完全二叉树。
🦆
为什么在发现第一个叶子节点后,还需要继续检查后续节点是否为叶子节点?
在完全二叉树中,一旦在某一层中出现了叶子节点(无子节点的节点),该层的所有后续节点以及所有更深层的节点都必须是叶子节点。这是因为完全二叉树的节点必须从左到右连续填充。如果在发现第一个叶子节点之后的任何位置出现非叶子节点,这将违反完全二叉树的定义,因此必须继续检查以确保所有后续节点都满足完全二叉树的条件。
🦆
您提到使用双端队列(deque),为什么选择双端队列而不是普通队列?
双端队列(deque)提供了从两端高效地添加和移除元素的能力。虽然在本题中主要使用了从左端出队和从右端入队的操作,这些操作在普通队列中也可以高效地完成。但是,使用双端队列可以为可能的需要进行双向操作提供灵活性,尤其是在其他需要频繁从队列两端操作的场景中。实际上,对于本题的需求,使用普通队列就足够了,因为我们主要是进行从队列一端的入队和出队操作。

相关问题