LeetCode Hot100 ---- 二叉树专题
作者:互联网
104. 二叉树的最大深度
根节点为第一层,经典必会。
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
return 1 + max([self.maxDepth(root.left), self.maxDepth(root.right)])
94. 二叉树的中序遍历
给定一个二叉树的根节点root,返回它的中序 遍历。
示例 1:
1
\
2
/
3
输出:[1,3,2]
思路:经典递归,必回。
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right)
98. 验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
思路:
- 得到中序遍历的结果;
- 判断中序遍历是否单调递增。
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
def get_mfs(root):
if not root:
return []
return get_mfs(root.left) +[root.val] + get_mfs(root.right)
res = get_mfs(root)
if len(res) <= 1:
return True
for i in range(1,len(res)):
if res[i] <= res[i-1]:
return False
return True
543. 二叉树的直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
class Solution:
def diameterOfBinaryTree(self, root: TreeNode) -> int:
self.ans = 1
def depth(node):
# 访问到空节点了,返回0
if not node:
return 0
# 左儿子为根的子树的深度
L = depth(node.left)
# 右儿子为根的子树的深度
R = depth(node.right)
# 计算d_node即L+R+1 并更新ans
self.ans = max(self.ans, L + R + 1)
# 返回该节点为根的子树的深度
return max(L, R) + 1
depth(root)
return self.ans - 1
102. 二叉树的层序遍历
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
3
/ \
9 20
/ \
15 7
返回其层序遍历结果:
[
[3],
[9,20],
[15,7]
]
思路:二叉树的题目很多适合用递归,因为二叉树本身就是由相同的节点结构组成。而此题用迭代实现更直观。
# 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 levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root: return []
#跟结点入queue
queue = [root]
res = []
while queue:
res.append([node.val for node in queue])
#存储当前层的孩子节点列表
ll = []
#对当前层的每个节点遍历
for node in queue:
#如果左子节点存在,入队列
if node.left:
ll.append(node.left)
#如果右子节点存在,入队列
if node.right:
ll.append(node.right)
#后把queue更新成下一层的结点,继续遍历下一层
queue = ll
return res
对于题目199,右视图即每层最右边的值,因此只需要做一个非常简单的小变化,即返回的列表只需要对每一层的列表的最后一个元素入结果列表就可以了
#只需要对该层最后一个元素入列表
res.append([node.val for node in queue][-1])
# 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 rightSideView(self, root: TreeNode) -> List[int]:
if not root: return []
#跟结点入queue
queue = [root]
res = []
while queue:
#只需要对该层最后一个元素入列表
res.append([node.val for node in queue][-1])
#存储当前层的孩子节点列表
ll = []
#对当前层的每个节点遍历
for node in queue:
#如果左子节点存在,入队列
if node.left:
ll.append(node.left)
#如果右子节点存在,入队列
if node.right:
ll.append(node.right)
#后把queue更新成下一层的结点,继续遍历下一层
queue = ll
return res
437. 路径总和 III
给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
基本思路:先回溯得到以根节点为起点(一定包含根节点)的路径和满足要求的总数。再深度优先搜索,即根节点路径数目+左节点路径数目+右节点路径数目
class Solution:
def pathSum(self, root: TreeNode, targetSum: int) -> int:
def backtrace(root, sum):
res = 0
if not root:
return res
if sum == root.val:
res += 1
if root.left:
res += backtrace(root.left, sum - root.val)
if root.right:
res += backtrace(root.right, sum - root.val)
return res
# 返回路径和等于数值的路径数
def DFS(root):
if not root:
return 0
root_count = backtrace(root, targetSum)
left_root = DFS(root.left)
right_root = DFS(root.right)
return left_root+right_root+root_count
return DFS(root)
617. 合并二叉树
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
示例 1:
输入:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
输出:
合并后的树:
3
/ \
4 5
/ \ \
5 4 7
注意: 合并必须从两个树的根节点开始。
思路:经典左右递归
class Solution:
def mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode:
if not t2:
return t1
elif not t1:
return t2
else:
t3 = TreeNode()
t3.val = t1.val + t2.val
t3.left = self.mergeTrees(t1.left,t2.left)
t3.right = self.mergeTrees(t1.right,t2.right)
return t3
226. 翻转二叉树
左右翻转一棵二叉树。
思路:经典左右递归
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return
root.left, root.right = self.invertTree(root.right), self.invertTree(root.left)
return root
114. 二叉树展开为链表
给定一个二叉树,原地将它展开为一个单链表。
1
/ \
2 5
/ \ \
3 4 6
将其展开为:
1
\
2
\
3
\
4
\
5
\
6
思路:前序遍历。
class Solution:
def flatten(self, root: TreeNode) -> None:
if not root:
return
# 先把左右两个子树处理成链表
self.flatten(root.left)
self.flatten(root.right)
# 接下来把右边链表剥离,把左边链表挂在root.right
tmp_right = root.right
root.right = root.left
root.left = None
# 然后把右边链表挂在原左边链表的最后
while root.right!=None:
root = root.right # 找到原左链表的末尾,用于接右链表
root.right = tmp_right
96. 不同的二叉搜索树
给定一个整数n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
思路:
考虑到根节点的左右子树也均为二叉搜索树,因此可以用递归:k为节点时,左子树为1...(k-1),右子树为(k+1)...n。
class Solution:
def numTrees(self, n: int) -> int:
dp = [0] * (n+1)
dp[0] = 1
dp[1] = 1
for i in range(1,n+1):
cnt = 0
for k in range(1,i+1):
cnt += dp[k-1]*dp[i-k]
dp[i] = cnt
return dp[n]
105. 从前序与中序遍历序列构造二叉树
根据一棵树的前序遍历与中序遍历构造二叉树, 树中没有重复的元素。
例如:
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回:
3
/ \
9 20
/ \
15 7
思路:前序遍历[根节点,左子树,右子树],中序遍历[左子树,根节点,右子树],显然前序遍历第一个为根节点,根据根节点在中序遍历中定位左右子树的中序遍历,同时可知左右子树的元素数量,由此在前序遍历中找到左右子树的前序遍历。由此递归。
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
if not preorder:
return
root = TreeNode()
root.val = preorder[0]
index = inorder.index(root.val)
root.left = self.buildTree(preorder[1:index+1],inorder[:index])
root.right = self.buildTree(preorder[index+1:],inorder[index+1:])
return root
236. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中。
思路:
某节点是公共祖先有两种情况:
- 该节点为指定节点中的一个,且子树中存在另一个节点。
- 该节点不是指定节点,但其左右子树均存在指定节点。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root:
return
if root==q or root==p:
return root # 可能为情况1,也可能是情况1中的子树
left = self.lowestCommonAncestor(root.left,p,q)
right = self.lowestCommonAncestor(root.right,p,q)
if left and right:
return root # 情况2
if not left:
return right
if not right:
return left
538. 把二叉搜索树转换为累加树
给出二叉搜索树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于node.val
的值之和。
思路:
后续遍历树,边遍历边维护一个和即可。
class Solution:
def __init__(self):
self.accum = 0
def convertBST(self, root: TreeNode) -> TreeNode:
if not root:
return
# 接下来逆中序遍历root
self.convertBST(root.right) # 1. 遍历右子树
root.val += self.accum # 2. 遍历当前结点
self.accum = root.val
self.convertBST(root.left) # 3. 遍历左子树
return root
337. 打家劫舍 III
二叉树的每个节点数字代表屋子中的金额,如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。
示例:
输入: [3,4,5,1,3,null,1]
3
/ \
4 5
/ \ \
1 3 1
输出: 9
解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.
思路:
对于每个节点,有两种状态:盗窃该节点和不盗窃。如果盗窃,则其左右子节点不能盗窃;如果不盗窃,则左右子节点也可以取两种状态。
class Solution:
def rob(self, root: TreeNode) -> int:
def helper(root):
'''
返回一个元组(rob, skip),分别代表偷root节点的总收益,和不偷的总收益。
总收益的意思是以root为根节点的子树的总收益。
'''
if not root:
return (0,0)
# 考虑以root为根节点的子树的收益, 偷了root就不能再偷左右子节点了
left_subtree = helper(root.left)
right_subtree = helper(root.right)
rob = root.val + left_subtree[1] +right_subtree[1]
skip = max(left_subtree) + max(right_subtree)
return rob, skip
return max(helper(root))
101. 对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
思路:
递归思路:
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
def is_sym(a,b):
if not a and not b:
return True
elif not a or not b:
return False
if a.val != b.val:
return False
return is_sym(a.left,b.right) and is_sym(a.right,b.left)
if not root:
return True
return is_sym(root.left,root.right)
迭代思路,一层一层遍历,每层查看是否对称:
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
layer = [root]
while layer:
vals = [root.val if root else None for root in layer ]
if vals!=vals[::-1]:
return False
layer = [(root.left, root.right) for root in layer if root]
layer = [i for tpl in layer for i in tpl]
return True
297. 二叉树的序列化与反序列化
将二叉树转化为字符串,并且可以将字符串再转化为原始的二叉树。
思路:
序列化的就是把数据结构转为字符串,可以使用DFS的方式,二叉树DFS的方法就是对每个节点,都先处理左子节点,再处理右子节点。
class Codec:
def serialize(self, root):
vals = []
def dfs(node):
if node:
vals.append(str(node.val))
dfs(node.left)
dfs(node.right)
else:
vals.append("#")
dfs(root)
s = " ".join(vals)
return s
def deserialize(self, data):
def redfs():
if vals:
val = vals.pop(0)
else:
return
if val == "#":
return None
node = TreeNode(int(val))
node.left = redfs()
node.right = redfs()
return node
vals = data.split(" ")
return redfs()
124. 二叉树中的最大路径和
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和 。
思路:
递归,对每个节点,最大值有四种情况:
- 仅该节点(比如左右子树都是负数)
- 该节点加左子树单链最大值
- 该节点加右子树单链的最大值
- 该节点加左右子树单链的最大值
class Solution:
def recur(self,root):
if not root:
return 0
left = self.recur(root.left)
right = self.recur(root.right)
left_right = left + root.val + right
tmpv = max(left+root.val, right+root.val, left_right, root.val)
if tmpv > self.maxv:
self.maxv = tmpv
return max(left, right, 0) + root.val
def maxPathSum(self, root: TreeNode) -> int:
self.maxv = root.val
_ = self.recur(root)
return self.maxv
标签:right,return,self,----,Hot100,二叉树,root,节点,left 来源: https://blog.csdn.net/zwqjoy/article/details/118464424