513.找树左下角的值
文档讲解:代码随想录
题目链接:. - 力扣(LeetCode)
递归法
分析一下题目:在树的最后一行找到最左边的值。首先要是最后一行,然后是最左边的值。
如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
(二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数)
递归的三要素:
第一要素:明确这个函数想要干什么
传入根节点,记录该根节点对应的二叉树的最大深度,更新二叉树的全局最大深度以及最大深度对应的最左边的数值(其实就是找到该节点对应的二叉树的最大深度)
第二要素:寻找递归结束条件
如果传入的是一个叶子节点,此时就可以判断记录的该二叉树的最大深度是否比我们之前记录的最大的深度要大,如果大的话,我们就要更新之前记录的全局最大深度和最大深度对应的最左边的数值
第三要素:找出函数的等价关系式
如果不是叶子节点,我们要找到该二叉树的最大深度,那么就可以分别看左子节点对应的二叉树的最大深度加1,和右子节点对应的二叉树的深度加1,因为我们要看的是左子节点,所以我们先记录左边的,如果右边的深度小于左边的,那么就不用更新,如果右边的大于左边的再更新
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
self.maxdepth = float('-inf')
self.value = None
self.traversal(root,0)
return self.value
def traversal(self,node,depth):
#终止条件,遇到了叶子节点
if node.left == None and node.right == None:
if depth > self.maxdepth:
self.maxdepth = depth
self.value = node.val
###递推
if node.left:
self.traversal(node.left,depth+1)
if node.right:
self.traversal(node.right,depth+1)
层序遍历
遍历到每一层的时候先记录下来最左边的数值,不断更新每一层对应的值,最后遍历完所有的曾层,该数值也就是最后一层的最左边的元素了
##层序遍历
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
que = deque()
value = 0
if not root:
return value
que.append(root)
while que:
for _ in range(len(que)):
node = que.popleft()
if _ == 0:
value = node.val
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
return value
112. 路径总和
文档讲解:代码随想录
题目链接:. - 力扣(LeetCode)
递归的三要素:
第一要素:明确这个函数想要干什么
传入根节点,判断二叉树是否有一条边之和是否正好是目标和
第二要素:寻找递归结束条件
不要去累加然后判断是否等于目标和,那么代码比较麻烦,可以用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值。
如果最后count == 0,同时到了叶子节点的话,说明找到了目标和(return true)。
如果遍历到了叶子节点,count不为0,就是没找到(return false)。
第三要素:找出函数的等价关系式
如果不是叶子节点,那么就需要向左子树或者右子树去寻找有没有满足条件的,即二叉树的左子树和右子树有没有符合条件的路径(true or false),如果都没有,那么就返回false
注意此时的count是减去根节点的了
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:
return False
return self.reversal(root,targetSum) #这里传入的targetSum是否减去当前值,决定了递归函数中终止条件是判断等于0,还是等于当前叶子节点值
def reversal(self,node,count):
##遍历到了叶子节点,##遇到了叶子节点count已经等于0/遇到了叶子节点count已经等于最后的差值
if node.left == None and node.right == None:
if count == node.val:
return True
else:
return False
##遇到了叶子节点count已经等于0/遇到了叶子节点count已经等于最后的差值
# if count == node.val and not node.left and not node.right:
# return True
# if not node.left and not node.right:
# return False
if node.left:
if self.reversal(node.left,count - node.val):
return True #只要有符合条件的就会返回
if node.right:
if self.reversal(node.right,count - node.val):
return True
return False
106.从中序与后序遍历序列构造二叉树
文档讲解:代码随想录
题目链接:. - 力扣(LeetCode)
参考视频:【数据结构 树和二叉树 考点二 由遍历序列确定二叉树】https://www.bilibili.com/video/BV1Je411N7b7?vd_source=be0fc400d3bbcf733b914e5ce518001e
递归的三要素:
第一要素:明确这个函数想要干什么
传入中序和后序遍历的数组,根据这两个数组 返回构造完的二叉树的根节点
第二要素:寻找递归结束条件
如果后序数组为0,return null
第三要素:找出函数的等价关系式
后续数组中的最后一个元素就是根节点,那么就可以定义一个新节点来保存找到的根节点
如果后序数组中只有这一个元素,那么就可以return 了
如果还有其他元素:
找到该元素在中序数组中的位置index,根据index切中序数组,得到左中序数组和右中序数组
切后序数组,根据上面得到的左数组的大小来切后序数组,得到的就是左后序和右后序
接下来就递归处理,root的左子树是递归处理上面切分好的左中序数组和左后序数组。root的右子树就是递归处理上面切分好的右中序和右后序数组。
步骤:
-
第一步:如果后序数组大小为零的话,说明是空节点了。
-
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
-
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点。
-
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
-
第五步:切割后序数组,切成后序左数组和后序右数组
-
第六步:递归处理左区间和右区间
class Solution:
##根据传入的中序和后序遍历,返回整个二叉树的节点
def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
#### 第一步: 特殊情况讨论: 树为空. (递归终止条件)
if len(postorder) == 0:
return None
#中序:左中右,后序:左右中
##后序数组不为空
# 第二步: 后序遍历的最后一个就是当前的中间节点.
root_val = postorder[-1]
root = TreeNode(root_val)
##如果只有一个节点
if len(postorder) == 1:
return root
##如果还有其他节点,递归
##找到该点在中序数组中的切割点
# 第三步: 找切割点.
for i in range(len(inorder)):
if inorder[i] == root_val:
break
#第四步:切割inorder数组. 得到inorder数组的左,右半边.
inorder_left = inorder[:i]
inorder_right = inorder[i+1:]
##第五步:根据inorder数组的左,右半边长度来切割postorder数组,得到postorder数组的左右半边
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