力扣题库110,判断一个二叉树是不是平衡二叉树。
题目链接点这里。
题目描述
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false 。
解题思路
题目中虽然用广度优先(BFS)的方式表示的二叉树,但是其实只需要知道根节点的地址即可代表一颗完整的树,答题框的提示也是这么说的
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
所以题目就只能从根节点入手,来判断一个二叉树是不是平衡二叉树。
因为必须所有的子树都要平衡,所以比较自然的想到利用递归,从根节点开始,逐层往下。当某节点的左右子树都平衡并且深度差不超过1则该节点代表的子树就是平衡的,再将结果依次合并上来。
这里不能直接获取到子树的深度,首先想到的也是利用另一个递归。所以就有了下面的初始答案。
初始答案
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def getDepth(node):
if not node:
return 0
else:
left = getDepth(node.left)
right = getDepth(node.right)
return max(left,right)+1
if root:
left = getDepth(root.left)
right = getDepth(root.right)
if abs(left-right)<2:
return self.isBalanced(root.left) and self.isBalanced(root.right)
else:
return False
else:
return True
这里的临时函数getDepth()
用来获取深度,用左右两边子树深度的最大值再加上1即可。而退出递归的条件就是传入的节点为None
,也就是叶节点的左右子节点,直接返回0。
isBalanced()
函数传入一个节点实例,退出递归也同样是传入的节点为None的时候。
这个答案确实正确,但是执行效率却很差。执行用时:104 ms,只击败了5.68%的提交。
计算一下时间复杂度。这里涉及到两层递归,主函数要对所有节点遍历一遍,而每个节点都要执行一次内部的递归,对该节点的所有子节点进行遍历。所以最坏情况总的遍历个数为(N-1)+(N-3)+(N-7)+...(N-M)
,一共有logN层,所以有logN个小括号。时间复杂度为O(NlogN)。
改进答案
因为只要有一个子树不平衡,整棵树就不平衡,所以其实在获取深度的时候就可以直接从下往上进行判断。当进行递归获取深度的时候,有任意节点不平衡,则直接返回一个标志位传递上来,整棵树就不平衡。这样就避免了明知道底下有树不平衡还要一直等到根节点才做最后的判断。
既然获取深度和判断平衡在一起进行了,这样只用一个递归就够用了。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def getDepth(node):
if not node:
return 0
else:
left = getDepth(node.left)
right = getDepth(node.right)
if left == -1 or right == -1:
return -1
elif abs(left-right)<2:
return max(left,right)+1
else:
return -1
if root:
if getDepth(root) == -1:
return False
else:
return True
else:
return True
如果有子树不平衡,直接返回-1,而在递归的时候只要左右子树有一个返回-1最后的结果就是-1,也就是不平衡。所以最坏的情况是一直到根节点才判断出来,也就是对所有节点都进行了遍历。时间复杂度为O(N)。
再次提交,执行用时:68 ms,击败了61.27%的提交。确实提升了很多。
注意事项
在写这道题的时候,一开始想将getDepth()
定义成一个静态方法,然后在实例方法中直接使用,发现不可以。看来我之前对类里面的静态方法有些误解,静态方法只能被实例或者是类调用,但是不能再类定义的内部被调用。所以如果说想写一个临时函数在类内部被调用,还是定义为实例方法比较好,然后名字前面加两个下划线只允许内部使用。
我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。