110. 平衡二叉树

110. 平衡二叉树

110. 平衡二叉树

给定一个二叉树,判断它是否是 平衡二叉树

平衡二叉树 是指该树所有节点的左右子树的深度相差不超过 1

示例 1:

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

示例 2:

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

示例 3:

输入:root = []
输出:true

提示:

  • 树中的节点数在范围 [0, 5000] 内
  • -10^4 <= Node.val <= 10^4

题外话

咋眼一看这道题目和104. 二叉树的最大深度(包括N叉树的最大深度)很像,其实有很大区别。

这里强调一波概念:

  • 二叉树节点的深度:指从根节点该节点的最长简单路径边的条数。
  • 二叉树节点的高度:指从该节点叶子节点的最长简单路径边的条数。

leetcode中强调的深度和高度很明显是按照节点来计算的,如图:
在这里插入图片描述

关于根节点的深度究竟是1 还是 0,不同的地方有不一样的标准,leetcode的题目中都是以节点为一度,即根节点深度是1。但维基百科上定义用边为一度,即根节点的深度是0,我们暂时以leetcode为准(毕竟要在这上面刷题)。

因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中) ,可以理解为深度是从上往下不断增加,而高度是从下往上不断增加。

有的同学一定疑惑,为什么104.二叉树的最大深度 中求的是二叉树的最大深度,也用的是后序遍历。

那是因为代码的逻辑其实是求的根节点的高度,而根节点的高度就是这棵树的最大深度,所以才可以使用后序遍历。如果是求某个中间节点的深度,则使用后序遍历可能会算错,比如上图中节点4的深度是3,如果按后序遍历求高度来算,会得到深度是2(但深度实际是3,高度才是2)

104.二叉树的最大深度 中,如果真正求取二叉树的最大深度,Go代码应该写成如下:(前序遍历)

/**
 * 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
    }
    // 使用前序遍历,不断更新最大深度的变量值
    res := 1
     dfs(root,1,&res)
    return res
}

func dfs(root *TreeNode,depth int,res *int)  {
    if *res < depth { // 中
        *res = depth
    }

    if root.Left != nil { // 左
        depth += 1 // 深度+1
        dfs(root.Left,depth,res)
        depth -= 1 // 回溯,深度-1
    }

    if root.Right != nil { // 右
        depth += 1 // 深度+1
        dfs(root.Right,depth,res)
        depth -= 1 // 回溯,深度-1
    }

}

可以看出使用了前序(中左右)的遍历顺序,这才是真正求深度的逻辑!

注意以上代码是为了把细节体现出来,简化一下代码如下:

/**
 * 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
    }
    // 使用前序遍历,不断更新最大深度的变量值
    res := 1
      dfs(root,1,&res)
    return res
}

func dfs(root *TreeNode,depth int,res *int)  {
    if *res < depth { // 中
        *res = depth
    }

    if root.Left != nil { // 左
        dfs(root.Left,depth + 1,res)
    }

    if root.Right != nil { // 右
        dfs(root.Right,depth + 1,res)
    }

}

本题思路

递归

此时大家应该明白了既然要求比较高度,必然是要后序遍历

递归三步曲分析:

  1. 明确递归函数的参数和返回值
    参数:当前传入节点。 返回值:当前节点为根的树是否是平衡二叉树
func isBalanced(root *TreeNode) bool {}
  1. 明确递归终止条件
    递归的过程中依然是遇到空节点了为终止,返回true,表示空节点可以当成平衡二叉树。另一个递归终止条件时,当前树已经明确不是平衡二叉树的时候,没必要继续往后继续递归了,而是应该往上层调用栈回归了。

代码如下:

    if root == nil {
        return true
    }

    // 左右子树高度绝对值相差大于1可以直接返回false了
    if int(math.Abs(float64(getDepth(root.Left) - getDepth(root.Right)))) > 1 {
        return false
    }
  1. 明确单层递归的逻辑
    当前根节点的左子树和右子树均为平衡二叉树

代码如下:

	left := isBalanced(root.Left)  // 左
    right := isBalanced(root.Right) // 右
    res := left && right // 根

最后本题整体递归代码如下:

Go代码

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func isBalanced(root *TreeNode) bool {
    // 以每一个节点作为根节点,判断他的左右子树高度之差是否小于等于1
    if root == nil {
        return true
    }

    // 左右子树高度绝对值相差大于1可以直接返回false了
    if int(math.Abs(float64(getDepth(root.Left) - getDepth(root.Right)))) > 1 {
        return false
    }

    left := isBalanced(root.Left)  // 左
    right := isBalanced(root.Right) // 右
    res := left && right // 根
    return res
}

// 求二叉树最大深度的模板代码
func getDepth(root *TreeNode) int{
    if root == nil {
        return 0
    }

    return max(getDepth(root.Left),getDepth(root.Right)) + 1
}

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

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值