一、找树左下角的值
1.1 题目
给定一个二叉树的 根节点 root
,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
示例 1:
输入: root = [2,1,3] 输出: 1
示例 2:
输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7
提示:
- 二叉树的节点个数的范围是
[1,10^4]
-2^31 <= Node.val <= 2^31 - 1
1.2 题目链接
1.3 解题思路和过程想法
(1)解题思路
层序遍历:利用层序遍历找到最后一层的第一个元素
递归遍历+回溯:利用递归找到左起第一个叶子节点(不论利用哪种递归都可以实现,因为左指针永远出现在右指针的前面,并且不用对根节点做任何操作),过程中用 level 记录当前层数,并利用回溯及时修改当前指针的 level,若遇到叶子节点则比较其层数与 maxLevel 的大小,若是更深层次的左叶子,则修改 maxLevel 和 res 。
(2)过程想法
利用层序遍历来找树左下角的值是比较简单的,也很好想;
递归遍历+回溯:其实也不难想,主要是要理解主体部分的逻辑和回溯,递归和回溯其实是分不开的,递归到一定深度并碰到出口之后就会向上回溯,此处只不过是需要及时修改一下回溯时用于记录层数的 level 变量,便于同等处理其他分支节点。
1.4 代码
1.4.1 层序遍历
from queue import Queue
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
# 利用层序遍历找到最后一层的第一个元素
myQueue = Queue()
if root:
myQueue.put(root)
while not myQueue.empty():
level = []
size = myQueue.qsize()
for i in range(size):
cur = myQueue.get()
level.append(cur.val)
if cur.left:
myQueue.put(cur.left)
if cur.right:
myQueue.put(cur.right)
return level[0]
1.4.2 递归遍历+回溯
class Solution:
def find(self,root,level):
# 递归出口
if not root.left and not root.right:
if level > self.maxLevel:
self.maxLevel = level
self.res = root.val
return
# 左
# 因为出口处没有判断root.left是否成立,所以此处进行判断
if root.left:
level += 1
self.find(root.left,level)
# 回溯
level -= 1
# 右
# 因为出口处没有判断root.right是否成立,所以此处进行判断
if root.right:
level += 1
self.find(root.right,level)
# 回溯
level -= 1
# 根:因为不需对根做操作,所以此处并未有对根的描述
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
# 前中后序遍历都可以,因为到最后都是左右的关系
self.res = root.val
self.maxLevel = 1
self.find(root,1)
return self.res
二、路径求和
2.1 题目
给定一个不重复的整数数组 nums
。 最大二叉树 可以用下面的算法从 nums
递归地构建:
- 创建一个根节点,其值为
nums
中的最大值。 - 递归地在最大值 左边 的 子数组前缀上 构建左子树。
- 递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums
构建的 最大二叉树 。
示例 1:
输入:nums = [3,2,1,6,0,5] 输出:[6,3,5,null,2,0,null,null,1] 解释:递归调用如下所示: - [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。 - [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。 - 空数组,无子节点。 - [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。 - 空数组,无子节点。 - 只有一个元素,所以子节点是一个值为 1 的节点。 - [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。 - 只有一个元素,所以子节点是一个值为 0 的节点。 - 空数组,无子节点。
示例 2:
输入:nums = [3,2,1] 输出:[3,null,2,null,1]
提示:
1 <= nums.length <= 1000
0 <= nums[i] <= 1000
nums
中的所有整数 互不相同
2.2 题目链接
2.3 解题思路和过程想法
(1)解题思路
前序遍历+回溯:
# 利用前序遍历,在过程中提前累加非空节点的值,一但找到符合要求的叶子节点,则更新结果self.res
# 若不符合,则在回溯时减去刚刚不符合要求节点的值以更新 summ 记录当前分支情况
(2)过程想法
因为已经写过类似”递归+回溯“的题了,所以思考的过程比较顺畅;回溯部分的代码是可以精简的,但因为是刚接触不久,所以写全了。
2.4 代码
class Solution:
def pathSum(self,root,summ):
# 利用前序遍历+回溯
# 递归出口:空节点和叶子节点
if not root:
return
if not root.left and not root.right:
if self.targetSum == summ:
self.res = True
return
# 左
if root.left:
summ += root.left.val
self.pathSum(root.left,summ)
summ -= root.left.val
# 右
if root.right:
summ += root.right.val
self.pathSum(root.right,summ)
summ -= root.right.val
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
# 利用前序遍历,在过程中提前累加非空节点的值,一但找到符合要求的叶子节点,则更新结果self.res
# 若不符合,则在回溯时减去刚刚不符合要求节点的值以更新 summ 记录当前分支情况
self.res = False
self.targetSum = targetSum
if root:
self.pathSum(root,root.val)
return self.res
else:
return False
三、从中序与后序遍历序列构造二叉树
3.1 题目
给定两个整数数组 inorder
和 postorder
,其中 inorder
是二叉树的中序遍历, postorder
是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
示例 1:
输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] 输出:[3,9,20,null,null,15,7]
示例 2:
输入:inorder = [-1], postorder = [-1] 输出:[-1]
提示:
1 <= inorder.length <= 3000
postorder.length == inorder.length
-3000 <= inorder[i], postorder[i] <= 3000
inorder
和postorder
都由 不同 的值组成postorder
中每一个值都在inorder
中inorder
保证是树的中序遍历postorder
保证是树的后序遍历
3.2 题目链接
3.3 解题思路和过程想法
(1)解题思路:
后序数组的最后节点——根节点,中序数组中:根节点左侧是左子树,根节点右侧是右子树
# 第一步:如果数组大小为零的话,说明是空节点了。
# 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
# 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
# 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
# 第五步:切割后序数组,切成后序左数组和后序右数组 (中序数组和后序数组的长度一定是相等的)
# 第六步:递归处理左区间和右区间
(2)过程想法:
之前每次写完都记不住,有思路但是每次都手足无措,希望这次写完之后能记住。
3.4 代码
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)
# 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
seperate_idex = inorder.index(root_val)
# 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
inorder_left = inorder[:seperate_idex]
inorder_right = inorder[seperate_idex+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