文章目录
前言
513.找树左下角的值
思路
本题掌握迭代法和递归法
迭代法十分直接
方法一 迭代法
层序遍历:输出最后一层的第一个叶子节点就行
具体实现:与层序遍历的区别在于,不需要保存每一层的每一个节点,只需要用一个值result保存每一层的第一个节点,反正result每一层都会被覆盖,直到最后一层;
from collections import deque
class Solution:
def findBottomLeftValue(self, root):
if root is None:
return 0
queue = deque()
queue.append(root)
result = 0
while queue:
size = len(queue)
for i in range(size):
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
方法二 递归法
两种方法都需要掌握
这个题目无论那种顺序都是不处理中节点的
总体思路:深度最大的叶子节点一定是最后一行;定义全局变量depth-max和result,如果有发现大于这个深度的,就更新depth-max和对应的result;
思路依据:无论哪种顺序的遍历,一定是先遍历左边,所以哪怕后面有相同深度的,result里面保存的也是最左边的。只有当深度大于已有的最大深度了,才会更新result
递归三部曲:
- 返回和输入:需要定义一个int来记录最长深度,还有一个result对应该深度的val
- 迭代终止:如果发现叶子节点了,比较更新max-depth和对应的result
- 单层迭代逻辑:如果有左节点,depth++,然后进入递归【先计数层数,再递归进入的】,然后记得depth–【回溯】,因为后面要进入右边
- 它 的整体逻辑是,当前遍历的是depth,在遍历过程中不断++和–【回溯】。原本就为1,先++,然后再进入新递归,然后左边递归会一直到叶子节点更新max-depth之后回来,然后–,进入右边。
这个代码要重新写,稍微修改了代码,教程里面result初始化为none是不对的,需初始化为root.val
- 它 的整体逻辑是,当前遍历的是depth,在遍历过程中不断++和–【回溯】。原本就为1,先++,然后再进入新递归,然后左边递归会一直到叶子节点更新max-depth之后回来,然后–,进入右边。
class Solution(object):
def traversal(self,root,depth):
if not root.left and not root.right:#叶子节点
if depth > self.max_depth:
self.max_depth = depth
self.result = root.val
return
if root.left:
depth += 1
self.traversal(root.left,depth)
depth -= 1
if root.right:
depth += 1
self.traversal(root.right,depth)
depth -= 1
def findBottomLeftValue(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:return
self.max_depth = 1
self.result = root.val
depth = 1
self.traversal(root,depth)
return self.result
112. 路径总和 113.路径总和ii
思路
优先掌握递归法
这个题目无法用何种方法遍历都是不处理中节点的
方法一
思路:和下面我的方法区别在于,是从target开始减,如果减到叶子节点为0,那么就说明是有的;
此外,直接返回了true和false
具体实现:和513类似,先减去了要进入的节点的值,再进入递归。[可以看三部曲,这里不放了]
注意精简版本中:
if self.traversal(cur.left, count): # 递归,处理节点
return True
count += cur.left.val # 回溯,撤销处理结果
可以写成if traversal(root.left,count-root.left.val): return True
class Solution:
def traversal(self, cur: TreeNode, count: int) -> bool:
if not cur.left and not cur.right and count == 0: # 遇到叶子节点,并且计数为0
return True
if not cur.left and not cur.right: # 遇到叶子节点直接返回
return False
if cur.left: # 左
count -= cur.left.val
if self.traversal(cur.left, count): # 递归,处理节点
return 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)
#精简版本
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if not root:
return False
if not root.left and not root.right and sum == root.val:
return True
return self.hasPathSum(root.left, sum - root.val) or self.hasPathSum(root.right, sum - root.val)
方法一2 迭代法(自己写的)
我听课之前自己写了一个,递归+回溯,sum到叶子节点如果等于的话就是【总体思路跟513一样】;
思路是:先加上,再进入递归。
class Solution(object):
def traversal(self,root):
if not root.left and not root.right and self.sum == self.targetSum:
return 1
if not root.left and not root.right and self.sum != self.targetSum:
return 0
if root.left:
self.sum += root.left.val
re = self.traversal(root.left)
if re == 1: return 1
self.sum -= root.left.val
if root.right:
self.sum += root.right.val
re = self.traversal(root.right)
if re == 1: return 1
self.sum -= root.right.val
return 0
def hasPathSum(self, root, targetSum):
"""
:type root: TreeNode
:type targetSum: int
:rtype: bool
"""
if root == None: return False
self.targetSum = targetSum
self.sum = root.val
re = self.traversal(root)
return True if re == 1 else False
方法二 递归法
113
💥result append的时候一定要append一个self.path[:] 复值的值
class Solution:
def __init__(self):
self.result = []
self.path = []
def traversal(self, cur, count):
if not cur.left and not cur.right and count == 0: # 遇到了叶子节点且找到了和为sum的路径
self.result.append(self.path[:])
return
if not cur.left and not cur.right: # 遇到叶子节点而没有找到合适的边,直接返回
return
if cur.left: # 左 (空节点不遍历)
self.path.append(cur.left.val)
count -= cur.left.val
self.traversal(cur.left, count) # 递归
count += cur.left.val # 回溯
self.path.pop() # 回溯
if cur.right: # 右 (空节点不遍历)
self.path.append(cur.right.val)
count -= cur.right.val
self.traversal(cur.right, count) # 递归
count += cur.right.val # 回溯
self.path.pop() # 回溯
return
def pathSum(self, root, targetSum):
# self.result.clear()
# self.path.clear()
if not root:
return self.result
self.path.append(root.val) # 把根节点放进路径
self.traversal(root, targetSum - root.val)
return self.result
106.从中序与后序遍历序列构造二叉树
后序和前序无法唯一地确定一个二叉树
思路
总体思路:由于是构造二叉树,所以每一次递归都是构建节点
说到一层一层切割,就应该想到了递归。
来看一下一共分几步:
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组【依据中序遍历的左边数组的大小来切,左边切出来了右边就有了】
第六步:递归处理左区间和右区间
递归三部曲
- 传入的是中序和后序
- 到了叶子节点,应该return这个节点
- 单层中,知道了根节点之后new一个node。然后给中序和后序分出一个左边和右边,分别进入递归,递归的结果就是左孩子和哟哟孩子
方法一 递归
自己写的注意事项:
1.如何判断到了叶子节点了:当前这一次递归中传入的posorder或者inorder的长度为1,那么就return 左右孩子为none的new的一个node
2. 切割后序遍历的左右的时候,一定要记得去除最后一个元素,那个是根节点使用[x:-1]的方法,不包括最后一个元素
3. 切片不算stop
# 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 traversal(self,):
def buildTree(self, inorder, postorder):
"""
:type inorder: List[int]
:type postorder: List[int]
:rtype: 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): - 1]
# 第六步: 递归
root.left = self.buildTree(inorder_left, postorder_left)
root.right = self.buildTree(inorder_right, postorder_right)
# 第七步: 返回答案
return root
方法二
105.从前序与中序遍历序列构造二叉树
思路
也是一样的思路,只不过从最后一个元素为根节点变成,第一个元素为根节点
class Solution(object):
def buildTree(self, preorder, inorder):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
if not inorder: return
root_val = preorder[0]
node = TreeNode(root_val)
if len(preorder) ==1:return node
seperate_index = inorder.index(root_val)
#seperate inorder
inorder_left = inorder[:seperate_index]
inorder_right = inorder[seperate_index+1:]
# seperat preorder
preorder_left = preorder[1:len(inorder_left)+1]
preorder_right = preorder[len(inorder_left)+1:]
node.left = self.buildTree(preorder_left,inorder_left)
node.right = self.buildTree(preorder_right,inorder_right)
return node