力扣刷题-二叉树-平衡二叉树

110 平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
image.png
返回 true 。
给定二叉树 [1,2,2,3,3,null,null,4,4]
image.png
返回 false 。

思路

参考:
https://www.programmercarl.com/0110.%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91.html#%E6%9C%AC%E9%A2%98%E6%80%9D%E8%B7%AF
强调一下概念:

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

但leetcode中强调的深度和高度很明显是按照节点来计算的,如图:
image.png
注意:leetcode的题目中都是以节点为一度,即根节点深度是1。
本题思路:

递归

此时大家应该明白了既然要求比较高度,必然是要后序遍历。
递归三步曲分析:

  1. 明确递归函数的参数和返回值

参数:当前传入节点。 返回值:以当前传入节点为根节点的树的高度。
那么如何标记左右子树是否差值大于1呢?
如果当前传入节点为根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了。
所以如果已经不是二叉平衡树了,**可以返回-1 **来标记已经不符合平衡树的规则了。

def get_height(self, node): # 递归一: 传入当前节点(以当前节点为根节点) 返回值为int 就是子树高度
  1. 明确终止条件

递归的过程中依然是遇到空节点了为终止,返回0,表示当前节点为根节点的树高度为0

if not node:
    return 0 # 递归二:如果节点不存在 显然该节点的高度为0 
  1. 明确单层递归的逻辑

如何判断以当前传入节点为根节点的二叉树是否是平衡二叉树呢?当然是其左子树高度和其右子树高度的差值。
分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1,表示已经不是二叉平衡树了。
严格按照 左右中 的写法 会更加清晰

# 单层递归逻辑 后序遍历思想 左右中 先分别求出其左右子树的高度
leftheight = self.get_height(node.left)
if leftheight == -1: # 采用-1表示非平衡了 左
    return -1
rightheight = self.get_height(node.right)
if rightheight == -1: # 采用-1表示非平衡了 右
    return -1
# 中
# 求左子树高度和其右子树高度的差值。分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1
if abs(leftheight-rightheight) > 1: # 差值大于1
    return -1
else:
    return 1 + max(leftheight, rightheight) # 一棵子树高度

最终的 get_height 代码:

def get_height(self, node): # 递归一: 传入当前节点(以当前节点为根节点) 返回值为int 就是子树高度
    if not node:
        return 0 # 递归二:如果节点不存在 显然该节点的高度为0 
    # 单层递归逻辑 后序遍历思想 左右中 先分别求出其左右子树的高度
    leftheight = self.get_height(node.left)
    if leftheight == -1: # 采用-1表示非平衡了 左
        return -1
    rightheight = self.get_height(node.right)
    if rightheight == -1: # 采用-1表示非平衡了 右
        return -1
    # 中
    # 求左子树高度和其右子树高度的差值。分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1
    if abs(leftheight-rightheight) > 1: # 差值大于1
        return -1
    else:
        return 1 + max(leftheight, rightheight) # 一棵子树高度

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

class TreeNode(object):
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution(object):
    def isBalanced(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        # if not root:
        #     return True 下面的递归函数 已经包含了 
        if self.get_height(root) != -1: # 采用 -1 来标识
            return True
        else:
            return False 
    
    def get_height(self, node): # 递归一: 传入当前节点(以当前节点为根节点) 返回值为int 就是子树高度
        if not node:
            return 0 # 递归二:如果节点不存在 显然该节点的高度为0 
        # 单层递归逻辑 后序遍历思想 左右中 先分别求出其左右子树的高度
        leftheight = self.get_height(node.left)
        if leftheight == -1: # 采用-1表示非平衡了 左
            return -1
        rightheight = self.get_height(node.right)
        if rightheight == -1: # 采用-1表示非平衡了 右
            return -1
        # 中
        # 求左子树高度和其右子树高度的差值。分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1
        if abs(leftheight-rightheight) > 1: # 差值大于1
            return -1
        else:
            return 1 + max(leftheight, rightheight) # 一棵子树高度
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于力扣刷C++常用操作,我可以给你一些常见的操作和技巧: 1. 使用 STL 容器和算法库:STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,包含了许多常用的容器和算法。在力扣刷中,使用 STL 可以大大提高代码的效率和可读性。例如,vector 可以用来存储动态数组,sort 可以用来排序等等。 2. 使用 auto 关键字:auto 关键字可以自动推导变量类型,可以减少代码量和提高可读性。例如,auto x = 1; 可以自动推导出 x 的类型为 int。 3. 使用 lambda 表达式:lambda 表达式是 C++11 中引入的一种匿名函数,可以方便地定义一些简单的函数对象。在力扣刷中,使用 lambda 表达式可以简化代码,例如在 sort 函数中自定义比较函数。 4. 使用位运算:位运算是一种高效的运算方式,在力扣刷中经常会用到。例如,左移运算符 << 可以用来计算 2 的幂次方,右移运算符 >> 可以用来除以 2 等等。 5. 使用递归:递归是一种常见的算法思想,在力扣刷中也经常会用到。例如,二叉树的遍历、链表的反转等等。 6. 使用 STL 中的 priority_queue:priority_queue 是 STL 中的一个容器,可以用来实现堆。在力扣刷中,使用 priority_queue 可以方便地实现一些需要维护最大值或最小值的算法。 7. 使用 STL 中的 unordered_map:unordered_map 是 STL 中的一个容器,可以用来实现哈希表。在力扣刷中,使用 unordered_map 可以方便地实现一些需要快速查找和插入的算法。 8. 使用 STL 中的 string:string 是 STL 中的一个容器,可以用来存储字符串。在力扣刷中,使用 string 可以方便地处理字符串相关的问。 9. 注意边界条件:在力扣刷中,边界条件往往是解决问的关键。需要仔细分析目,考虑各种边界情况,避免出现错误。 10. 注意时间复杂度:在力扣刷中,时间复杂度往往是评判代码优劣的重要指标。需要仔细分析算法的时间复杂度,并尽可能优化代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值