getDepth()和isBalanced()都在递归,getDepth()就是前面做过的求树最大深度;isBalanced()的逻辑是:判断平衡树应该要比较当前节点的左右子树最大深度,若相差不超过1,再接着判断左孩子的两个子树、右孩子的两个子树,退出递归的条件是节点为空。只有在当前节点、左孩子、右孩子都满足条件时是平衡二叉树。
class Solution:
def getDepth(self, root):
if not root:
return 0
return 1 + max(self.getDepth(root.left), self.getDepth(root.right))
def isBalanced(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
if abs(self.getDepth(root.left) - self.getDepth(root.right)) > 1:
return False
else:
return self.isBalanced(root.left) and self.isBalanced(root.right)
P.S. 讨论一下树的高度与深度:在上题getDepth()和之前的求二叉树最大深度题目中, 由于根节点的高度==二叉树的深度,我们求的是根节点高度。如果题目要求找到值==val的节点的深度,就需要用求深度的逻辑写代码。下面用求深度的逻辑写getDepth():
class Solution:
def getDepth(self, node, depth, res):
if not node:
res[0] = max(res[0], depth-1)
return
self.getDepth(node.left, depth+1, res)
self.getDepth(node.right, depth+1, res)
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
res = [0]
self.getDepth(root, 1, res)
return res[0]
* res是用list封装int,传入函数;
* 递归调用getDepth()时传入depth+1,其实是在做回溯;
* 易错:当节点为空,记得比较res和depth-1而非depth,因为空节点不算数。
1)递归+回溯
易错1:path.append(str(node.val)),否则paths.append("->".join(path))时执行出错;
易错2:不可以直接paths.append(path),否则在后面path.pop()会连带影响paths;
易错3:回溯,即path.pop()的位置、次数。
class Solution:
def getPath(self, node, path, paths):
path.append(str(node.val))
if not (node.left or node.right): #is leaf
paths.append("->".join(path))
path.pop()
return
elif not node.left:
self.getPath(node.right, path, paths)
path.pop()
elif not node.right:
self.getPath(node.left, path, paths)
path.pop()
else:
self.getPath(node.left, path, paths)
self.getPath(node.right, path, paths)
path.pop()
def binaryTreePaths(self, root):
if not root:
return []
path = []
paths = []
self.getPath(root, path, paths)
return paths
调整与一下path.pop()的位置,使得每次递归(调用self.getPath)时紧跟一个回溯path.pop():
class Solution:
def getPath(self, node, path, paths):
path.append(str(node.val))
if not (node.left or node.right): #is leaf
paths.append("->".join(path))
return
elif not node.left:
self.getPath(node.right, path, paths)
path.pop()
elif not node.right:
self.getPath(node.left, path, paths)
path.pop()
else:
self.getPath(node.left, path, paths)
path.pop()
self.getPath(node.right, path, paths)
path.pop()
def binaryTreePaths(self, root):
if not root:
return []
path = []
paths = []
self.getPath(root, path, paths)
return paths
再简化一下条件判断:(记得避免将空节点传入self.getPath)
class Solution:
def getPath(self, node, path, paths):
path.append(str(node.val))
if not (node.left or node.right): #is leaf
paths.append("->".join(path))
return
if node.left:
self.getPath(node.left, path, paths)
path.pop()
if node.right:
self.getPath(node.right, path, paths)
path.pop()
def binaryTreePaths(self, root):
if not root:
return []
path = []
paths = []
self.getPath(root, path, paths)
return paths
* 补充:Python的参数传递机制
x = 10 # 全局变量
def modify_immutable():
global x # 使用global关键字声明
print("Before modification:", x)
x = 20
print("After modification:", x)
print("Original x:", x) # 输出: Original x: 10
modify_immutable() # 修改全局变量x的值
print("Modified x:", x) # 输出: Modified x: 20
my_list = [1, 2, 3] # 全局变量
def modify_mutable():
print("Before modification:", my_list)
my_list.append(4) # 直接修改全局列表
print("After modification:", my_list)
print("Original my_list:", my_list) # 输出: Original my_list: [1, 2, 3]
modify_mutable() # 修改全局列表
print("Modified my_list:", my_list) # 输出: Modified my_list: [1, 2, 3, 4]
2)迭代,用两个栈存放节点和其对应的路径。每次弹出栈中的节点和从root到该节点的路径(字符串),若为叶子节点,对应路径推入结果列表,若不是叶子,再将非空孩子节点与对应的路径推入两个栈。
class Solution:
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
if not root:
return []
paths = [str(root.val)]
nodes = [root]
res = []
while nodes:
node = nodes.pop()
path = paths.pop()
if not node.left and not node.right:
res.append(path)
else:
if node.left:
nodes.append(node.left)
paths.append(path + "->" + str(node.left.val))
if node.right:
nodes.append(node.right)
paths.append(path + "->" + str(node.right.val))
return res
* cnt:python int不可变,要用list封装。
class Solution:
def func(self, node, cnt):
if node.left:
if not self.notleaf(node.left): #left node is leaf
cnt[0] += node.left.val
else: #left node is not leaf
self.func(node.left, cnt)
if node.right:
if self.notleaf(node.right): #right node is not leaf
self.func(node.right, cnt)
def notleaf(self, node):
return node.left or node.right
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
cnt = [0]
self.func(root, cnt)
return cnt[0]
更简洁的解法:
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
if root.left and not root.left.left and not root.left.right:
return root.left.val + self.sumOfLeftLeaves(root.left) + self.sumOfLeftLeaves(root.right)
else:
return self.sumOfLeftLeaves(root.left) + self.sumOfLeftLeaves(root.right)
或者
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
tmp = self.sumOfLeftLeaves(root.left) + self.sumOfLeftLeaves(root.right)
if root.left and not root.left.left and not root.left.right:
return root.left.val + tmp
else:
return tmp