513 树左下角的值
给定一个二叉树,在树的最后一行找到最左边的值。
这个题是左边边的值,并不是左子树,右子树的也可以,不然理解错了。
这个题用层序遍历的方式是很简单的,到最后一层,取第一个,就行了
层序遍历
def findBottomLeftValue(root):
from collections import deque
queue = deque([root])
result = 0
while queue:
for i in range(len(queue)):
node = queue.popleft()
if i == 0:
result = node.val
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
递归遍历
说到要找最左边,采用遍历方式前序遍历就可以
核心在于 最低层 最左边
递归三部曲:
1. 递归参数和返回值 因为要计算深度 因此参数是节点和深度
2. 递归中止条件:
not node 返回
叶子节点,判断当前深度 进行赋值,在这里,因为我们加了判断深度,且优先遍历左子树,如果左边有叶子节点满足,赋值了,那么之后同一层的叶子节点由于高度一样,不会再次被赋值
左子树
右子树
class solution:
def findBottomLeftValue(self, root):
if not root:
return None
self.max_depth = -1
self.result = 0
self.dfs(root, 0)
return self.result
def dfs(self, root, depth):
if not root.left and not root.right:
if depth > self.max_depth:
self.result = root.val
self.max_depth = depth
return
if root.left:
depth += 1
self.dfs(root.left, depth)
depth -= 1
if root.right:
depth += 1
self.dfs(root.right, depth)
depth -= 1
112. 路径总和
给你二叉树的根节点 root
和一个表示目标和的整数 targetSum
。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum
。如果存在,返回 true
;否则,返回 false
。
叶子节点 是指没有子节点的节点。
这个你完全可以按照遍历所有路径的思路去写,然后只要有一个路径满足就可以了。
但是这样会多跑,就算你前面判断有某条路径可以了,但是你还是会继续走。麻烦
所以可以优化。我的思路是设置一个全局的变量,当第一次满足的时候去改变它,后面就判断是否改变,如果改变了,就不遍历,没有,就继续遍历
def hasPathSum(self, root, targetSum):
if not root:
return False
self.targetSum = targetSum
self.flag = False
self.dfs(root, path=[])
return self.flag
def dfs(self, root, path):
path.append(root.val)
if not root.left and not root.right:
sum_ = sum(path)
if sum_ == self.targetSum:
self.flag = True
return
if root.left:
if !self.flag:
self.dfs(root.left, path)
path.pop()
if root.right:
if !self.flag:
self.dfs(root.right, path)
path.pop()
这个题目还是可以继续改善
你可以不采用列表求和,而是在递归过程中直接相减。
此外,你可以让输出返回值,当遇到符合条件的子路径就返回
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:
return False
return self.tranversal(root, targetSum-root.val)
def tranversal(self, node, count):
if node.left == None and node.right == None and count == 0:
return True
if node.left == None and node.right == None:
return False
if node.left:
count -= node.left.val
if self.tranversal(node.left, count):
return True
count += node.left.val
if node.right:
count -= node.right.val
if self.tranversal(node.right, count):
return True
count += node.right.val
return False
113. 路径总和2
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例: 给定如下二叉树,以及目标和 sum = 22,其实也和遍历所有路径一个思路 只不过判断条件不一样。
106.从中序与后序遍历序列构造二叉树
中序 左中右
后序 左右中
思路就是用后序得到根节点
然后用得到的根节点去中序分割左右子树
然后再用中序的左右子树去区分后序的左右子树
这样就得到了 root的左子树和右子树 在进行递归 直到最后的叶节点。
核心在于分割区间,然后边界条件的确定。统一边界条件,左闭右开。
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
if not postorder:
return None
# 第二步: 后序遍历的最后一个就是当前的中间节点.
root_val = postorder[-1]
root = TreeNode(root_val)
# 第三步: 找切割点.
separator_idx = inorder.index(root_val)
# 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
inorder_left = inorder[:separator_idx]
inorder_right = inorder[separator_idx + 1:]
# 第五步: 切割postorder数组. 得到postorder数组的左,右半边.
# ⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的.
postorder_left = postorder[:len(inorder_left)]
postorder_right = postorder[len(inorder_left): len(postorder) - 1]
# 第六步: 递归
root.left = self.buildTree(inorder_left, postorder_left)
root.right = self.buildTree(inorder_right, postorder_right)
# 第七步: 返回答案
return root
前序遍历也是一样,只不过要注意区间分割,代码如下。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
if not preorder: return None
root_val = preorder[0]
root = TreeNode(root_val)
index = inorder.index(root_val)
# 切割中序
inorder_left = inorder[: index]
inorder_right = inorder[index+1:]
# 切割前序
preorder_left = preorder[1: 1+len(inorder_left)]
preorder_right = preorder[1+len(inorder_left):]
root.left = self.buildTree(preorder_left, inorder_left)
root.right = self.buildTree(preorder_right, inorder_right)
return root