给定一个二叉树,判断它是否是高度平衡的二叉树。
递归解法:
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
def cal_height(root) -> int:
if not root: return 0
return max(cal_height(root.left), cal_height(root.right)) + 1
if not root: return True
m = cal_height(root.left)
n = cal_height(root.right)
if abs(m - n) > 1:
return False
return self.isBalanced(root.left) and self.isBalanced(root.right)
给你一个二叉树的根节点root
,按任意顺序 ,返回所有从根节点到叶子节点的路径。
这一题需要用到回溯,也是我第一次接触,很有意思。
尤其注意里面的path[:],不加后面的[:]会出问题,不加把path的地址传到paths里了,而加了[:]才是传具体的元素。
class Solution:
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
# 思路:先序遍历
# 1. 定义函数参数和返回值:没有返回值,不断在paths里添加路径
path = []
paths = []
def construct_path(root):
# 2. 定义结束条件:
if not root:
return
path.append(root.val)
# 3. 递归时的操作
# 如果是叶子节点,加入到paths中
if not root.left and not root.right:
paths.append(path[:]) # 注意一定要加[:]
return
# 左右孩子加入路径,返回上一级要回溯;
if root.left:
construct_path(root.left)
path.pop()
if root.right:
construct_path(root.right)
path.pop()
construct_path(root)
# 第一次我写了两个for循环T_T。可以利用两个小技巧美化代码
# 1. map可以根据提供的函数对指定序列做映射;
# 2. for循环的一行代码形式的写法
ans = ['->'.join(map(str,i)) for i in paths]
return ans
给定二叉树的根节点 root
,返回所有左叶子之和。
思路1 每次遇到左叶子节点就往总和s上加。
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
def isLeftLeaf(root):
return root and not root.left and not root.right
ans = 0
def dfs(root):
nonlocal ans # 不加nonlocal会报错:local variables 'ans' referenced before assignment
#终止条件
if not root: return 0
if isLeftLeaf(root.left):
ans = ans + root.left.val #根
dfs(root.left) # 左
dfs(root.right) # 右
dfs(root)
return ans
至于为什么要写nonlocal,因为外部的ans在inner scope里面不可以reassignment。而如果ans=[],内部进行ans.append(1)是可以的,因为[]是mutable的,改了之后没有进行reassignment。
可以参照上面一题中的paths.append(path[:])。首先,按照上面的解释,paths.append是可以修改外部的paths的。问题又来了,为什么[:]不能省略呢?因为下一次如果path指向的list改变了,那么之前加进来的path也跟着变化了,加了[:]就表示具体的元素。
下面两个链接是这个问题的很好的回答,mark。
https://stackoverflow.com/questions/64323757/why-does-python-3-8-0-allow-to-change-mutable-types-from-enclosing-function-scop
Facts and myths about Python names and values | Ned Batchelder
思路2 某个节点的左叶子之和就是左孩子的左叶子之和➕右孩子的左叶子之和。如果左孩子是结点,加上它自己的值。
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
def isLeftLeaf(root):
return root and not root.left and not root.right
if not root: return 0
m = self.sumOfLeftLeaves(root.left)
n = self.sumOfLeftLeaves(root.right)
return m+n+root.left.val if isLeftLeaf(root.left) else m + n