找树左下角的值
层序遍历法
这道题用层序遍历还是挺好做的
# 层序遍历解法
from collections import deque
class Solution:
def findBottomLeftValue(self, root: TreeNode | None) -> int:
queue=deque()
if root==None:
return
queue.append(root)
while queue:
result=queue[0].val # 每遍历一层,都把最左侧的值更新一下
for _ in range(len(queue)):
node=queue.popleft()
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
递归法
class Solution:
def findBottomLeftValue(self, root: TreeNode | None) -> int:
max_depth=0
result=None
def traversal(node:TreeNode,depth:int):
nonlocal max_depth
nonlocal result
if node.left is None and node.right is None:
if depth>max_depth:
max_depth=depth
result=node.val
if node.left:
depth+=1
traversal(node.left,depth)
depth-=1
if node.right:
depth+=1
traversal(node.right,depth)
depth-=1
traversal(root,1)
return result
递归三部曲:
- 参数是节点和当前深度,无返回值
- 终止条件是叶子节点,且深度最大就记录结果
- 单层递归逻辑就是先递归左,再递归右,另外深度还有一个回溯的过程
我一开始是终止条件没想对,这个终止条件和二叉树的全部路径有点像,到了叶子节点就到了收获的时候了。这道题还额外要求了得是最大深度才行。
然后是单层递归逻辑,就是先递归左再递归右,有深度的记录,所以要回溯一下。
因为是先遍历左,再遍历右,所以如果同样是最大深度的一层,记录了左就不会记录右边了。
路径总和
# 错误解法
class Solution:
def hasPathSum(self, root: TreeNode | None, targetSum: int) -> bool:
if root is None:
return False
result=False
def hasPS(node:TreeNode,_sum=0):
nonlocal result
if result is True:
return
_sum+=node.val
if node.left is None and node.right is None:
result= _sum==targetSum
return
if node.left:
hasPS(node.left,_sum)
_sum-=node.left.val # _sum不用手动回溯
if node.right:
hasPS(node.right,_sum)
_sum-=node.right.val # 删掉
hasPS(root)
return result
这里我看代码随想录题型这道题有回溯,所以就在这加了回溯,但其实这里返回上一层的时候,这个_sum就自动恢复成上一层的_sum了,不用手动再减去下一层的值。
需不需要回溯,关键就是看回到上一层的时候,需要恢复的值有没有自动恢复,自动恢复了就不需要手动回溯了。
代码随想录里这道题的解法属于自己给自己找麻烦了
路径总和Ⅱ
class Solution:
def pathSum(self, root: TreeNode | None, targetSum: int) -> list[list[int]]:
result=[]
if root is None:
return result
def findpath(node:TreeNode,path=None):
nonlocal result
if path is None:
path=[]
path.append(node.val)
if node.left is None and node.right is None and sum(path)==targetSum:
result.append(path[:]) #不能写path[]
if node.left:
findpath(node.left,path)
path.pop()
if node.right:
findpath(node.right,path)
path.pop()
findpath(root)
return result
这里就需要pop了,这属于是 python 的特性了。我的理解是:每一层递归里的 path 都是局部变量,但它们指向的是同一个列表对象。所以递归返回上一层的时候,列表不会自动回溯,需要手动回溯。保存结果的时候也需要写[:],否则指向的就是同一个列表对象,后续如果这个列表对象有改动,结果里也会跟着变动。
中序后序构造二叉树
这道题挺有意思的,自己想虽然想不到,但是背下来倒是很简单
class Solution:
def buildTree(self, inorder: list[int], postorder: list[int]) -> TreeNode | None:
if postorder==[]: #任意一个数组为空就返回
return
root_val=postorder[-1]
root=TreeNode(root_val)
inorder_root_index=inorder.index(root_val)
inorder_left=inorder[:inorder_root_index]
inorder_right=inorder[inorder_root_index+1:]
postorder_left=postorder[:len(inorder_left)]
postorder_right=postorder[len(inorder_left):-1]
root.left=self.buildTree(inorder_left,postorder_left)
root.right=self.buildTree(inorder_right,postorder_right)
return root
这道题的逻辑大概是这样的:
- 后序数组的最后一位是根节点
- 根据根节点,到中序数组中划分出左子树元素和右子树元素
- 根据左子树的长度到后序数组中找出左子树,右子树
- 递归:输入左子树的中序和后序构造左子树最后把左子树的根节点返回给root,右子树同理
这道题要注意区间,保持区间不变性,保持左闭右开区间。
前序中序构造二叉树跟这道题思路差不多