写在前边的话
今天是二叉树训练的第四天,二叉树相关的理论知识在第一天中已经总结了可见下边链接,看今天题目也是比较多的,那就开始吧。
找树左下角的值
题目链接
题目难度
中等
看到题目的第一想法
看到题目的第一想法是想利用层序遍历,遍历每层节点的过程中使用数组保存当前层节点数据,知道最后一层,然后返回数组的第一个数据。
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:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
queue = collections.deque([root])
while queue:
tmp = []
n = len(queue)
for i in range(n):
node = queue.popleft()
tmp.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return tmp[0]
看完代码随想录之后的总结
文章讲解
视频讲解
解题思路
递归法
1. 遍历顺序:前中后都可以,因为没有中的处理逻辑
2. 递归三部曲:
入参:当前节点以及深度;不用返回值。
终止条件:找到叶子节点,更新最大深度,如果当前节点深度大于最大深入则还需要获取节点的值。
单次递归逻辑:左节点不为空,递归遍历左子树;右节点不为空,递归遍历右子树;注意需要有回溯。
迭代法
1. 看完代码随想录以后, 没有必要找个列表保存数据,直接保存每层第一个数据就可以了。
代码编写
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:
def reversal(self, node, depth):
if not node.left and not node.right:
if depth > self.max_depth:
self.max_depth = depth
self.res = node.val
return
if node.left:
depth += 1
self.reversal(node.left, depth)
depth -= 1 # 回溯
if node.right:
depth += 1
self.reversal(node.right, depth)
depth -= 1 # 回溯
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
self.max_depth = float('-inf')
self.res = None
self.reversal(root, 0)
return self.res
#**********************************************************************
# 迭代法
# 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 findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
queue = collections.deque([root])
while queue:
res = 0
n = len(queue)
for i in range(n):
node = queue.popleft()
if i == 0:
res = node.val
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return res
java
路径总和
112. 路径总和
题目链接
题目难度
简单
看到题目的第一想法
由于前边有写过找二叉树路径的题目用的是递归法,因此看到题目的第一想法就想用递归来解决。
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:
def reversal(self, node, targetSum):
if not node.left and not node.right:
if sum(self.path) == targetSum:
self.res = True
if node.left:
self.path.append(node.left.val)
self.reversal(node.left, targetSum)
self.path.pop()
if node.right:
self.path.append(node.right.val)
self.reversal(node.right, targetSum)
self.path.pop()
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:
return False
self.path = [root.val]
self.res = False
self.reversal(root, targetSum)
return self.res
注意:
代码不足点:1. 这个代码需要遍历所有的路径,没有做到找到目标路径以后就直接返回,增加了时间复杂度。 2. 使用的是列表保存路径,最后求和,这样会增加时间复杂度和空间复杂度。其实写算法的时候想到了这些问题,但是没找到好的解决办法。
看完代码随想录之后的总结
文章讲解
视频讲解
解题思路
递归法
1. 遍历顺序:前中后都可以,因为没有中的处理逻辑。
2. 递归三部曲:
入参:根节点以及目标值;返回值:布尔值
终止条件:当前节点的左右节点均为空且目标值减为0,返回true;当前节点的左右节点均为空且目标值不为0,返回false。
单次递归逻辑:左:遍历左节点不为空则目标值减去左节点的值;然后继续遍历左子树,如果返回true则继续像上一层返回true;目标值加上左节点的值(回溯)。右:遍历右节点不为空则目标值减去右节点的值;然后继续遍历右子树,如果返回true则继续像上一层返回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:
def reversal(self, node, count):
# 终止条件
if not node.left and not node.right and count == 0:
return True
if not node.left and not node.right and count != 0:
return False
# 单层递归逻辑
if node.left:
count -= node.left.val
if self.reversal(node.left, count): # 如果找到了一条路径则直接返回了不会进行下边的逻辑了
return True
count += node.left.val # 回溯
if node.right:
count -= node.right.val
if self.reversal(node.right, count):
return True
count -= node.right.val
return False
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:
return False
return self.reversal(root, targetSum-root.val)
java
113. 路径总和||
题目链接
题目难度
中等
看到题目的第一想法
看到题目的时候和上边那道题目一样,使用递归法解决。
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:
def reversal(self, node, path, targetSum, res):
if not node.left and not node.right:
if sum(path) == targetSum:
res.append(path[:]) # 注意这里需要使用切片或者深拷贝
if node.left:
path.append(node.left.val)
self.reversal(node.left, path, targetSum, res)
path.pop()
if node.right:
path.append(node.right.val)
self.reversal(node.right, path, targetSum, res)
path.pop()
return res
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
if not root:
return []
path = [root.val]
res = []
return self.reversal(root, path, targetSum, res)
注意:添加列表到结果列表的时候,由于入参是列表,因此递归的时候列表中的数据一直在变,因此需要使用切片或深拷贝添加。
看完代码随想录之后的总结
解题思路
递归法
解题思路和上边的题目是相似的不同的是需要获取到所有的目标路径并进行保存。
1. 遍历顺序:前中后都可以,因为没有中的处理逻辑。
2. 递归三部曲:
入参:根节点以及目标值;返回值:布尔值
终止条件:当前节点的左右节点均为空且目标值减为0,添加当前路径到结果列表中然后返回;当前节点的左右节点均为空且目标值不为0,直接返回。
单次递归逻辑:左:遍历左节点不为空,添加左节点到路径中;然后目标值减去左节点的值;然后继续遍历左子树;目标值加上左节点的值并且路径pop(回溯)。右:遍历右节点不为空,添加右节点到路径中;然后目标值减去右节点的值;然后继续遍历右子树;目标值加上右节点的值并且路径pop(回溯)。
代码编写
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:
def __init__(self):
self.path = []
self.res = []
def reversal(self, node, count):
if not node.left and not node.right and count == 0:
self.res.append(self.path[:])
return
if not node.left and not node.right and count != 0:
return
if node.left:
self.path.append(node.left.val)
count -= node.left.val
self.reversal(node.left, count)
count += node.left.val
self.path.pop()
if node.right:
self.path.append(node.right.val)
count -= node.right.val
self.reversal(node.right, count)
count += node.right.val
self.path.pop()
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
if not root:
return []
self.path.append(root.val)
self.reversal(root, targetSum-root.val)
return self.res
java
从中序与后序遍历序列构造二叉树
题目链接
力扣题目链接
题目难度
中等
看到题目的第一想法
看到这个题目,没有想到比较好的解决办法。
看完代码随想录之后的总结
文章讲解
视频讲解
解题思路
1. 递归法
2. 解题步骤
1)树为空了,则返回空(递归终止条件)
2)后序遍历的最后一个元素就是当前的中间节点
3)在中序遍历中查找切割点
4)切割中序遍历的数组,切割为左中序和右中序
5)切割后序遍历的数组
6)递归
代码编写
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:
def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
if not postorder:
return None
root_val = postorder[-1]
root = TreeNode(root_val)
root_index = inorder.index(root_val)
inorder_left = inorder[:root_index]
inorder_right = inorder[root_index + 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
105.从前序与中序遍历序列构造二叉树
解题思路同上。
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:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
if not preorder:
return None
root_val = preorder[0]
root = TreeNode(root_val)
root_index = inorder.index(root_val)
print(f"root_index: {root_index}")
inorder_left = inorder[:root_index]
inorder_right = inorder[root_index+1:]
preorder_left = preorder[1: len(inorder_left)+1]
preorder_right = preorder[len(inorder_left)+1:]
root.left = self.buildTree(preorder_left, inorder_left)
root.right = self.buildTree(preorder_right, inorder_right)
return root
今日总结
今天也是用递归解题的一天,感觉更加熟悉了,只要有思路然后按照递归三步曲(入参返回值、终止条件、单次递归逻辑)按部就班的来思考就问题不会特别大了。然后是今天构造二叉树的题目,由于没接触过这类题目,没什么思路,训练完思路也是比较清晰了(前序和中序、后序和中序均可以唯一确定二叉树,前序和后序不能,因为必须要有中序才能确定左右部分才能进行分割)。