Leetcode刷题笔记16:二叉树3(104.二叉树的最大深度-111.二叉树的最小深度-559 n叉树的最大深度 22.完全二叉树节点个数)

160 阅读5分钟

导语

leetcode刷题笔记记录,本篇博客记录二叉树部分的题目,主要题目包括:

知识点

二叉树的高度与深度

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始)
  • Leetcode上所有题目深度和高度都从1开始

完全二叉树

一个二叉树是完全二叉树当且仅当满足以下两个条件:

  1. 所有的层(除了最后一层外)都被完全填满。这意味着每一层(从根开始,直到倒数第二层)都有可能的最大节点数。
  2. 在最后一层,所有的节点都尽可能集中在左边,即如果最后一层不是完全填满的,那么空缺的位置应该都在最右边。

根据这种定义,完全二叉树的所有节点都有一个唯一的位置,与它们在数组中的索引相对应(如果将二叉树的节点存储在数组中,并按层次遍历的顺序)。这种特性使得完全二叉树经常被用于实现堆数据结构。

Leetcode 104 二叉树的最大深度

题目描述

给定一个二叉树 root ,返回其最大深度。二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

示例 1:

输入: root = [3,9,20,null,null,15,7]
输出: 3

解法

根节点的高度就是二叉树的最大深度,这道题目等价于求最大高度,所以可以采用后序遍历来方便的实现。

class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        return self.getMaxHeight(root)

    def getMaxHeight(self, root):
        if not root: return 0;
        leftHeight = self.getMaxHeight(root.left)
        rightHeight = self.getMaxHeight(root.right)
        return 1 + max(leftHeight, rightHeight)

Leetcode 559 n叉树的最大深度

题目描述

给定一个 N 叉树,找到其最大深度。最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。 N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。

示例 1:

输入: root = [1,null,3,2,4,null,5,6]
输出: 3

解法

与二叉树类似,这里的n叉树则需要借助一个数组heights来收集这n个children的高度,同时如果一个节点没有children,那么应该返回1。

class Solution:
    def maxDepth(self, root: 'Node') -> int:
        return self.getMaxHeight(root)

    def getMaxHeight(self, root):
        if not root: return 0
        if not root.children: return 1
        heights = []
        for child in root.children:
            height = self.getMaxHeight(child)
            heights.append(height)
        return 1+max(heights)

Leetcode 111 二叉树的最小深度

题目描述

给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。说明: 叶子节点是指没有子节点的节点。

示例 1:

输入: root = [3,9,20,null,null,15,7]
输出: 2

解法

这个题目如果直接套用最大深度的代码,只改max为min的话会导致错误,因为如果这样,代码会统计到某个缺少左孩子或右孩子的节点就停止,而不是叶子节点,比如下面的情况下,回直接返回1(因为根节点没有左子树)。

IMG_2696C4651F1E-1.jpeg

为此,需要在最终返回值时进行判断,避免掉这种情况,具体代码如下:

class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        return self.getMinHeight(root)

    def getMinHeight(self, root):
        if not root: return 0;
        leftHeight, rightHeight = self.getMinHeight(root.left), self.getMinHeight(root.right)
        if leftHeight == 0 and rightHeight != 0:
            return 1+rightHeight
        elif leftHeight != 0 and rightHeight == 0:
            return 1+leftHeight
        else:
            return 1+min(leftHeight, rightHeight)

Leetcode 222 完全二叉树的节点个数

题目描述

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

 

示例 1:

输入: root = [1,2,3,4,5,6]
输出: 6

解法

这道题完全可以采用层次遍历法,代码如下:

from collections import deque

class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        queue = deque()
        count = 0
        if root:
            queue.append(root)
        while queue:
            size = len(queue)
            for _ in range(size):
                node = queue.popleft()
                count += 1
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
        return count

但这样的复杂度是O(N)O(N),而且没有利用好完全二叉树的性质。完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。

  • 对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
  • 对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。

具体实现代码如下:

class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        left, right = root.left, root.right
        left_depth, right_depth = 0, 0
        while left:
            left = left.left
            left_depth += 1
        while right:
            right = right.right
            right_depth += 1
        if left_depth == right_depth:
            return 2 ** (left_depth+1) - 1
        left_num = self.countNodes(root.left)
        right_num = self.countNodes(root.right)
        result = left_num + right_num + 1

        return result