代码随想录算法训练营第18天|二叉树part05|513.找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树
513.找树左下角的值
自己做
思路:
最底层、最左边
层次遍历
返回result[-1][0]就是
代码:
python
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def findBottomLeftValue(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:
return -1
queue = deque()
queue.append(root)
result = []
while len(queue):
level = []
for _ in range(len(queue)):
cur = queue.popleft()
level.append(cur.val)
if cur.left: queue.append(cur.left)
if cur.right: queue.append(cur.right)
result.append(level)
return result[-1][0]
路径总和
112. 路径总和
自己做
思路:
我知道本题使用回溯法来做,但是再判断完是否curSum==targetSum后,在递归中,如何返回这个bool类型的值到原函数中呢?卡在了这里
代码:
python(看完讲解自己编写)
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def hasPathSum(self, root, targetSum):
"""
:type root: TreeNode
:type targetSum: int
:rtype: bool
"""
# dequeue = deque() # 用于存放从根结点到当前结点走过的路径
if not root:
return False
curSum = 0 # 用于存放从很结点到当前结点的累加和
curSum += root.val
return self.helper(root, curSum, targetSum)
def helper(self, root, curSum, targetSum):# 1.
# 2.
if not root.left and not root.right and curSum == targetSum:
return True
if not root.left and not root.right:
return False
# 3.
if root.left:
curSum += root.left.val
if self.helper(root.left, curSum, targetSum): return True
curSum -= root.left.val
if root.right:
curSum += root.right.val
if self.helper(root.right, curSum, targetSum): return True
curSum -= root.right.val
return False
代码随想录
思路:
相信很多同学都会疑惑,递归函数什么时候要有返回值,什么时候没有返回值,特别是有的时候递归函数返回类型为bool类型。
递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
-
如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
-
如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
-
如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
递归处理
只要找到一条符合条件的路径,就要及时返回,不再递归下去, 一直返回到出递归
怎么才能从叶子结点如果为True的话就一直返回到出递归呢?
if not root.left and not root.right and curSum == targetSum:
return True
# 意思就是只要返回值为True, 就不再递归下去,直接出递归
if self.helper(root.left) : return true
if self.helper(root.right) : return true
代码:
python
# 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:
# 1 确定递归函数的参数和返回类型
def traversal(self, cur: TreeNode, count: int) -> bool:
# 2. 确定终止条件
if not cur.left and not cur.right and count == 0: # 遇到叶子节点,并且计数为0
return True
if not cur.left and not cur.right: # 遇到叶子节点直接返回
return False
# 3. 确定单层递归的逻辑
if cur.left: # 左
count -= cur.left.val
if self.traversal(cur.left, count): # 递归,处理节点
return True # 只要为True,就不再递归下去,就返回了
count += cur.left.val # 回溯,撤销处理结果
if cur.right: # 右
count -= cur.right.val
if self.traversal(cur.right, count): # 递归,处理节点
return True
count += cur.right.val # 回溯,撤销处理结果
return False
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if root is None:
return False
return self.traversal(root, sum - root.val)
迭代
# 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 hasPathSum(self, root: TreeNode, sum: int) -> bool:
if not root:
return False
# 此时栈里要放的是pair<节点指针,路径数值>
st = [(root, root.val)]
while st:
node, path_sum = st.pop()
# 如果该节点是叶子节点了,同时该节点的路径数值等于sum,那么就返回true
if not node.left and not node.right and path_sum == sum:
return True
# 右节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if node.right:
st.append((node.right, path_sum + node.right.val))
# 左节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if node.left:
st.append((node.left, path_sum + node.left.val))
return False
113. 路径总和 II
自己做
思路:
求所有路径 -> 回溯法 + 需要一个path[] + result[]
代码:
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def __init__(self):
self.result = []
self.path = []
def pathSum(self, root, targetSum):
"""
:type root: TreeNode
:type targetSum: int
:rtype: List[List[int]]
"""
if not root:
return []
curSum = 0
curSum += root.val
self.path.append(root.val)
self.helper(root, curSum, targetSum)
return self.result
def helper(self, root, curSum, targetSum): # 1.
# 2.
if not root.left and not root.right and curSum == targetSum:
#print(self.path)
self.result.append(list(self.path))
return
if not root.left and not root.right:
return
# 3.
if root.left:
curSum += root.left.val
self.path.append(root.left.val)
#print(self.path)
self.helper(root.left, curSum, targetSum)
curSum -= root.left.val
self.path.pop()
if root.right:
curSum += root.right.val
self.path.append(root.right.val)
self.helper(root.right, curSum, targetSum)
curSum -= root.right.val
self.path.pop()
迭代
# 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 pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
if not root:
return []
stack = [(root, [root.val])]
res = []
while stack:
node, path = stack.pop()
if not node.left and not node.right and sum(path) == targetSum:
res.append(path)
if node.right:
stack.append((node.right, path + [node.right.val]))
if node.left:
stack.append((node.left, path + [node.left.val]))
return res
从中序与后序遍历序列构造二叉树
106.从中序与后序遍历序列构造二叉树
自己做
思路:
- 中序遍历 inorder = [9,3,15,20,7] 左中右
- 后序遍历 postorder = [9,15,7,20,3] 左右中
-> 后序遍历的最后一个结点为根结点 3
-> 根据 3 去中序遍历可以区分左右子树
-> 根据左右子树可以去后续遍历剩余元素中区分开左子树序列和右子树序列
-> 去后序遍历子树序列中寻找最后一个元素,找到子树的根结点
-> 循环反复,直到列表为空
代码:自己没做出来
python
代码随想录
思路:
如果让我们肉眼看两个序列,画一棵二叉树的话,应该分分钟都可以画出来。
那么代码应该怎么写呢?
说到一层一层切割,就应该想到了递归。
来看一下一共分几步:
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组
第六步:递归处理左区间和右区间
代码:代码是按照自己敲的
python
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def buildTree(self, inorder, postorder):
"""
:type inorder: List[int]
:type postorder: List[int]
:rtype: TreeNode
"""
# 1.
if len(postorder) == 0:
return None
# 2.
root = TreeNode(postorder[-1])
# 3.
if len(postorder) == 1:
return root
# 4.
delimiterIndex = 0
for index, val in enumerate(inorder):
if val == root.val:
delimiterIndex = index
break
# 5. 切割中序数组,得到 中序左数组和中序右数组
left_inorder = inorder[:delimiterIndex]
right_inorder = inorder[delimiterIndex+1:]
# 6. 切割后序数组,得到 后序左数组和后序右数组
left_postorder = postorder[:len(left_inorder)]
right_postorder = postorder[len(left_inorder):-1]
# 7.
root.left = self.buildTree(left_inorder, left_postorder)
root.right = self.buildTree(right_inorder, right_postorder)
return root
105.从前序与中序遍历序列构造二叉树
自己做
思路:
-> 前序遍历列表第一个元素为根结点
-> 接下来的思路与上题一致
代码:
python
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def buildTree(self, preorder, inorder):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
if len(preorder) == 0:
return None
root = TreeNode(preorder[0])
if len(preorder) == 1:
return root
delimiterIndex = 0
for index, val in enumerate(inorder):
if val == root.val:
delimiterIndex = index
break
left_inorder = inorder[ : delimiterIndex]
right_inorder = inorder[delimiterIndex+1: ]
left_preorder = preorder[1:len(left_inorder)+1]
right_preorder = preorder[len(left_inorder)+1: ]
root.left = self.buildTree(left_preorder, left_inorder)
root.right = self.buildTree(right_preorder, right_inorder)
return root
注意
前序和中序可以唯一确定一棵二叉树。
后序和中序可以唯一确定一棵二叉树。
那么前序和后序可不可以唯一确定一棵二叉树呢?
前序和后序不能唯一确定一棵二叉树!
反例: