目录
剑指 Offer 32 - II. 从上到下打印二叉树 II
剑指 Offer 32 - III. 从上到下打印二叉树 III
二叉树遍历
前序遍历:先访问根节点,再前序遍历左子树,再前序遍历右子树
中序遍历:先中序遍历左子树,再访问根节点,再中序遍历右子树
后序遍历:先后序遍历左子树,再后序遍历右子树,再访问根节点
注意点
-
以根访问顺序决定是什么遍历
-
左子树都是优先右子树
二叉树三种遍历递归
class TreeNode:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def create_binary_tree(input_list=[]):
"""
构建二叉树
:param input_list: 输入数列
"""
if input_list is None or len(input_list) == 0:
return None
data = input_list.pop(0)
if data is None:
return None
node = TreeNode(data)
node.left = create_binary_tree(input_list)
node.right = create_binary_tree(input_list)
return node
def pre_order_traversal(node):
"""
前序遍历
:param node: 二叉树节点
"""
if not node :
return
print(node.data)
pre_order_traversal(node.left)
pre_order_traversal(node.right)
return node
def in_order_traversal(node):
"""
中序遍历
:param node: 二叉树节点
"""
if not node:
return
in_order_traversal(node.left)
print(node.data)
in_order_traversal(node.right)
return node
def post_order_traversal(node):
"""
后序遍历
:param node: 二叉树节点
"""
if not node :
return
post_order_traversal(node.left)
post_order_traversal(node.right)
print(node.data)
return node
my_input_list = list([3, 2, 9, None, None, 10, None, None, 8, None, 4])
root = create_binary_tree(my_input_list)
print("前序遍历:")
pre_order_traversal(root)
print("中序遍历:")
in_order_traversal(root)
print("后序遍历:")
post_order_traversal(root)
144.二叉树的前序遍历 非递归
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack=[]
res=[]
while root or stack:
while root:
res.append(root.val)
stack.append(root)
root=root.left
root=stack.pop()
root=root.right
return 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 inorderTraversal(self, root: TreeNode) -> List[int]:
res=[]
def helper(root):
if not root:
return
res.append(root.val)
helper(root.left)
helper(root.right)
helper(root)
return res
94. 二叉树的中序遍历 非递归
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack=[]
res=[]
while root or stack:
while root:
stack.append(root)
root=root.left
root=stack.pop()
res.append(root.val)
root=root.right
return 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 inorderTraversal(self, root: TreeNode) -> List[int]:
res=[]
def helper(root):
if not root:
return
helper(root.left)
res.append(root.val)
helper(root.right)
helper(root)
return res
145. 二叉树的后序遍历 非递归
创建的二叉树如下:
后序遍历为:5 3 2 4 1
先序遍历为:1 2 5 3 4
逆后序遍历为:1 4 2 3 5
从逆后序遍历与先序遍历的关系中我们可以知道逆后序遍历序列为先序遍历交换左右子树的遍历顺序得到的,所以我们得到了逆后序序列之后然后逆序就可以得到后序遍历的序列了,所以需要两个栈,第一个栈用来存储先序遍历交换左右子树的遍历的中介结果,第二个是存储后序遍历的结果(逆序也就是可以理解为先进后出的意思)
下面是模仿元素进栈与出栈的过程:
① 1节点进栈,在循环中弹出1节点压入到第二个栈中,发现左右节点不为空那么将左右节点压入栈1,这个与先序遍历中将左右子树压入到栈顶的顺序是相反的
② 弹出4节点压入到第二个栈中,发现左右孩子都为空那么不进行任何的操作
③ 弹出2节点压入到第二个栈中,发现左右节点不为空那么将左右节点压入到栈1中
④ 弹出3节点压入到第二个栈中,发现左右孩子都为空不进行任何操作
⑤ 弹出5节点压入到第二个栈中,发现左右孩子都为空不进行任何操作
最后栈为空那么退出循环结束
# 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 postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack1=[]
stack2=[]
res=[]
#完全按照前序遍历的思路,只是调换了left和right的顺序
while root or stack1:
while root:
stack1.append(root)
stack2.append(root.val)
root=root.right
root=stack1.pop()
root=root.left
while stack2:
res.append(stack2.pop())
return res
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack1 = []
stack2 = []
node = root
res=[]
stack1.append(node)#根节点
# 这个while循环的功能是找出后序遍历的逆序,存在stack2里面
while stack1:
node = stack1.pop()
if node.left:
stack1.append(node.left)
if node.right:
stack1.append(node.right)
stack2.append(node)
# 将stack2中的元素出栈,即为后序遍历次序
while stack2:
res.append(stack2.pop().val)
return 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 postorderTraversal(self, root: TreeNode) -> List[int]:
res=[]
def helper(root):
if not root:
return
helper(root.left)
helper(root.right)
res.append(root.val)
helper(root)
return res
104. 二叉树的最大深度
剑指 Offer 55 - I. 二叉树的深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7]
,
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
# 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 maxDepth(self, root: TreeNode) -> int:
if root is None:
return 0
else:
left_height = self.maxDepth(root.left)
right_height = self.maxDepth(root.right)
return max(left_height, right_height) + 1
110. 平衡二叉树
剑指 Offer 55 - II. 平衡二叉树
难度简单366
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true
。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false
。
# 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 isBalanced(self, root: TreeNode) -> bool:
def height(root: TreeNode) -> int:
if not root:
return 0
leftHeight = height(root.left)
rightHeight = height(root.right)
if leftHeight == -1 or rightHeight == -1 or abs(leftHeight - rightHeight) > 1:
return -1
else:
return max(leftHeight, rightHeight) + 1
return height(root) >= 0
124. 二叉树中的最大路径和
难度困难575
给定一个非空二叉树,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。
示例 1:
输入: [1,2,3]
1
/ \
2 3
输出: 6
示例 2:
输入: [-10,9,20,null,null,15,7]
-10
/ \
9 20
/ \
15 7
输出: 42
class Solution:
def __init__(self):
self.maxSum = float("-inf")
def maxPathSum(self, root: TreeNode) -> int:
def maxGain(node):
if not node:
return 0
# 递归计算左右子节点的最大贡献值
# 只有在最大贡献值大于 0 时,才会选取对应子节点
leftGain = max(maxGain(node.left), 0)
rightGain = max(maxGain(node.right), 0)
# 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
priceNewpath = node.val + leftGain + rightGain
# 更新答案
self.maxSum = max(self.maxSum, priceNewpath)
# 返回节点的最大贡献值
return node.val + max(leftGain, rightGain)
maxGain(root)
return self.maxSum
112. 路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。
叶子节点 是指没有子节点的节点。
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
# 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 hasPathSum(self, root: TreeNode, targetSum: int) -> bool:
if not root:
return False
if root.val == targetSum and not root.left and not root.right:
return True
left = self.hasPathSum(root.left, targetSum - root.val)
right = self.hasPathSum(root.right, targetSum - root.val)
return left or right
113. 路径总和 II
剑指 Offer 34. 二叉树中和为某一值的路径
难度中等408
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22
,
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]
]
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
ret = list()
path = list()
def dfs(root: TreeNode, total: int):
if not root:
return
path.append(root.val)
total -= root.val
if not root.left and not root.right and total == 0:
ret.append(path[:])
dfs(root.left, total)
dfs(root.right, total)
path.pop()
dfs(root,sum)
return ret
二叉树框架
226. 翻转二叉树
剑指 Offer 27. 二叉树的镜像
这道题目比较简单,关键思路在于我们发现翻转整棵树就是交换每个节点的左右子节点,于是我们把交换左右子节点的代码放在了前序遍历的位置。如果把交换左右子节点的代码放在后序遍历的位置也是可以的,但是放在中序遍历的位置是不行的,请你想一想为什么?这个应该不难想到,我会把答案置顶在公众号留言区。
中序遍历换节点 根据左根右的遍历顺序 相当于左侧节点交换了两次 右侧节点没换 因为遍历根的时候交换了左右节点 遍历右侧的时候还是之前那个左节点。
示例:
输入:
4
/
2 7
/ \ /
1 3 6 9
输出:
4
/
7 2
/ \ /
9 6 3 1
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
前序遍历
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
root.left,root.right=root.right,root.left
self.invertTree(root.left)
self.invertTree(root.right)
return root
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
后序遍历
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
left=self.invertTree(root.left)
right=self.invertTree(root.right)
root.left=right
root.right=left
return root
116. 填充每个节点的下一个右侧节点指针
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node { int val; Node *left; Node *right; Node *next;}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
进阶:你只能使用常量级额外空间。使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
示例:
输入:root = [1,2,3,4,5,6,7]
输出:[1,#,2,3,#,4,5,6,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,’#’ 标志着每一层的结束。
"""
# Definition for a Node.
class Node:
def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return root
self.connectTwoNode(root.left,root.right)
return root
def connectTwoNode(self,node1,node2):
if node1==None or node2==None:
return
node1.next=node2
self.connectTwoNode(node1.left,node1.right)
self.connectTwoNode(node1.right,node2.left)
self.connectTwoNode(node2.left,node2.right)
101. 对称二叉树
剑指 Offer 28. 对称的二叉树
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/ \
2 2
/ \ / \
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/ \
2 2
\ \
3 3
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
if not root:
return True
def dfs(left,right):
# 递归的终止条件是两个节点都为空
if not left and not right:
return True
# 或者两个节点中有一个为空
if not left or not right:
return False
# 或者两个节点的值不相等
if left.val!=right.val:
return False
return dfs(left.left,right.right) and dfs(left.right,right.left)
# 用递归函数,比较左节点,右节点
return dfs(root.left,root.right)
114. 二叉树展开为链表
给定一个二叉树,原地将它展开为一个单链表。
例如,给定二叉树
1
/
2 5
/ \
3 4 6
将其展开为:
1
2
3
4
5
6
# 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 flatten(self, root: TreeNode) -> None:
"""
Do not return anything, modify root in-place instead.
"""
if not root:
return root
#注意输出为空,二叉树只使用右节点就是链表
self.flatten(root.left)
self.flatten(root.right)
# 后序遍历位置
# 1、左右子树已经被拉平成一条链表
a=root.left
b=root.right
#2、将左子树作为右子树
root.left=None
root.right=a
# 3、将原先的右子树接到当前右子树的末端
p=root
while p.right:
p=p.right
p.right=b
654. 最大二叉树
给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:
二叉树的根是数组 nums 中的最大元素。
左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。
右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。
返回有给定数组 nums 构建的 最大二叉树 。
对于每个根节点,只需要找到当前nums中的最大值和对应的索引,然后递归调用左右数组构造左右子树即可。
# 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 constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
if not nums:
return None
maxval=nums[0]
index=0
for i,num in enumerate(nums):
if num>maxval:
maxval=num
index=i
root=TreeNode(maxval)
root.left=self.constructMaximumBinaryTree(nums[:index])
root.right=self.constructMaximumBinaryTree(nums[index+1:])
return root
105. 从前序与中序遍历序列构造二叉树
剑指 Offer 07. 重建二叉树
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/
9 20
/
15 7
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def buildTree(self, preorder, inorder):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
if len(inorder) == 0:
return None
# 前序遍历第一个值为根节点
root = TreeNode(preorder[0])
# 因为没有重复元素,所以可以直接根据值来查找根节点在中序遍历中的位置
mid = inorder.index(preorder[0])
# 构建左子树
root.left = self.buildTree(preorder[1:mid+1], inorder[:mid])
# 构建右子树
root.right = self.buildTree(preorder[mid+1:], inorder[mid+1:])
return root
- 从中序与后序遍历序列构造二叉树
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
"""
:type postorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
if len(inorder) == 0:
return None
# 后序遍历最后一个值为根节点
root = TreeNode(postorder[-1])
# 因为没有重复元素,所以可以直接根据值来查找根节点在中序遍历中的位置
mid = inorder.index(postorder[-1])
# 构建左子树
root.left = self.buildTree(inorder[:mid], postorder[:mid])
# 构建右子树
root.right = self.buildTree(inorder[mid+1:], postorder[mid:-1])
return root
652. 寻找重复的子树
给定一棵二叉树,返回所有重复的子树。对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。
两棵树重复是指它们具有相同的结构以及相同的结点值。
示例 1:
1
/
2 3
/ /
4 2 4
/
4
下面是两个重复的子树:
2
/
4
和 4
Counter
Counter是一个简单的计数器,例如,统计字符出现的个数:
>>> from collections import Counter
>>> c = Counter()
>>> for ch in 'programming':
... c[ch] = c[ch] + 1
...
>>> c
Counter({'g': 2, 'm': 2, 'r': 2, 'a': 1, 'i': 1, 'o': 1, 'n': 1, 'p': 1})
Counter实际上也是dict的一个子类,上面的结果可以看出,字符'g'、'm'、'r'各出现了两次,其他字符各出现了一次。
# 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 findDuplicateSubtrees(self, root: TreeNode) -> List[TreeNode]:
count = collections.Counter()
ans = []
def collect(node):
if not node: return "#"
# serial = "{},{},{}".format(node.val, collect(node.left), collect(node.right))
serial =str(node.val) + ',' + collect(node.left) + ',' + collect(node.right)
count[serial] += 1
if count[serial] == 2:
ans.append(node)
return serial
collect(root)
return ans
剑指 Offer 26. 树的子结构
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
例如:
给定的树 A:
3
/ \
4 5
/ \
1 2
给定的树 B:
4
/
1
返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。
示例 1:
输入:A = [1,2,3], B = [3,1]
输出:false
示例 2:
输入:A = [3,4,5,1,2], B = [4,1]
输出:true
class Solution:
def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
if not A or not B:
return False
def recur(A, B):
if not B: return True
if not A or A.val != B.val: return False
return recur(A.left, B.left) and recur(A.right, B.right)
return recur(A, B) or self.isSubStructure(A.left, B) or self.isSubStructure(A.right, B)
剑指 Offer 37. 序列化二叉树
请实现两个函数,分别用来序列化和反序列化二叉树。
示例:
你可以将以下二叉树:
1
/ \
2 3
/ \
4 5
序列化为 "[1,2,3,null,null,4,5]"
注意:本题与主站 297 题相同:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/
class Codec:
def serialize(self, root):
if not root: return "[]"
queue = collections.deque()
queue.append(root)
res = []
while queue:
node = queue.popleft()
if node:
res.append(str(node.val))
queue.append(node.left)
queue.append(node.right)
else: res.append("null")
return '[' + ','.join(res) + ']'
def deserialize(self, data):
if data == "[]": return
vals, i = data[1:-1].split(','), 1
root = TreeNode(int(vals[0]))
queue = collections.deque()
queue.append(root)
while queue:
node = queue.popleft()
if vals[i] != "null":
node.left = TreeNode(int(vals[i]))
queue.append(node.left)
i += 1
if vals[i] != "null":
node.right = TreeNode(int(vals[i]))
queue.append(node.right)
i += 1
return root
二叉树层序遍历
剑指 Offer 32 - I. 从上到下打印二叉树
从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
class Solution:
def levelOrder(self, root: TreeNode) -> List[int]:
res = []
if not root:
#注意返回[]
return res
queue = [root]
while queue:
node = queue.pop(0)
res.append(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
return res
102. 二叉树的层序遍历
剑指 Offer 32 - II. 从上到下打印二叉树 II
3
/ \
9 20
/ \
15 7
返回其层序遍历结果:
[
[3],
[9,20],
[15,7]
]
https://leetcode-cn.com/problems/binary-tree-level-order-traversal/solution/die-dai-di-gui-duo-tu-yan-shi-102er-cha-shu-de-cen/
二叉树的层序遍历非递归
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
res = []
if not root:
#注意返回[]
return res
res = []
queue = [root]
while queue:
# 获取当前队列的长度,这个长度相当于 当前这一层的节点个数
size = len(queue)
tmp = []
# 将队列中的元素都拿出来(也就是获取这一层的节点),放到临时list中
# 如果节点的左/右子树不为空,也放入队列中
for _ in range(size):
r = queue.pop(0)
tmp.append(r.val)
if r.left:
queue.append(r.left)
if r.right:
queue.append(r.right)
# 将临时list加入最终返回结果中
res.append(tmp)
return res
二叉树的层序遍历递归
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
res = []
if not root:
return res
def helper(node, level):
if not node:
return
if level == len(res):
res.append([])
res[level].append(node.val)
helper(node.left, level + 1)
helper(node.right, level + 1)
helper(root, 0)
return res
107. 二叉树的层次遍历 II
难度简单252
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
例如:
给定二叉树 [3,9,20,null,null,15,7]
,
3
/ \
9 20
/ \
15 7
返回其自底向上的层次遍历为:
[
[15,7],
[9,20],
[3]
]
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
res = []
if not root:
return res
queue = [root]
while queue:
# 获取当前队列的长度,这个长度相当于 当前这一层的节点个数
size = len(queue)
tmp = []
# 将队列中的元素都拿出来(也就是获取这一层的节点),放到临时list中
# 如果节点的左/右子树不为空,也放入队列中
for _ in range(size):
r = queue.pop(0)
tmp.append(r.val)
if r.left:
queue.append(r.left)
if r.right:
queue.append(r.right)
# 将临时list加入最终返回结果中
res.append(tmp)
return res[::-1]
103. 二叉树的锯齿形层次遍历
剑指 Offer 32 - III. 从上到下打印二叉树 III
难度中等212
给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:
给定二叉树 [3,9,20,null,null,15,7]
,
3
/ \
9 20
/ \
15 7
返回锯齿形层次遍历如下:
[
[3],
[20,9],
[15,7]
]
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
res = []
que = [root]
if root == None:
return res
while que:
tempList = []
for i in range(len(que)):
node = que.pop(0)
tempList.append(node.val)
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
res.append(tempList)
temp = []
for i in range(len(res)):
if i%2 == 0:
temp.append(res[i])
else:
temp.append(res[i][::-1])
return temp
二叉搜索树
230. 二叉搜索树中第K小的元素
给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。
说明:
你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。
示例 1:
输入: root = [3,1,4,null,2], k = 1
3
/
1 4
2
输出: 1
示例 2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/
3 6
/
2 4
/
1
输出: 3
一个直接的思路就是升序排序,然后找第k个元素呗。BST 的中序遍历其实就是升序排序的结果,找第k个元素肯定不是什么难事。
# 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 kthSmallest(self, root: TreeNode, k: int) -> int:
res=[]
def inorder(r):
if not r:
return None
inorder(r.left)
res.append(r.val)
inorder(r.right)
return res
return inorder(root)[k - 1]
剑指 Offer 54. 二叉搜索树的第k大节点
给定一棵二叉搜索树,请找出其中第k大的节点。
示例 1:
输入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
输出: 4
示例 2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
输出: 4
限制:1 ≤ k ≤ 二叉搜索树元素个数
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def kthLargest(self, root: TreeNode, k: int) -> int:
res=[]
def inorder(r):
if not r:
return None
inorder(r.right)
res.append(r.val)
inorder(r.left)
return res
return inorder(root)[k - 1]
538. 把二叉搜索树转换为累加树
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
提醒一下,二叉搜索树满足下列约束条件:
节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。
从大到小降序打印 BST 节点的值,如果维护一个外部累加变量sum,然后把sum赋值给 BST 中的每一个节点,不就将 BST 转化成累加树了吗?
# 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 convertBST(self, root: TreeNode) -> TreeNode:
sum = 0
def traversal(root: TreeNode):
# nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量。
nonlocal sum
if root:
traversal(root.right)
sum =sum+ root.val
root.val =sum
traversal(root.left)
traversal(root)
return root
98. 验证二叉搜索树
难度中等641
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:
2
/
1 3
输出: true
示例 2:
输入:
5
/
1 4
/
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。
# 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 isValidBST(self, root: TreeNode) -> bool:
"""
:type root: TreeNode
:rtype: bool
"""
def helper(node, lower = float('-inf'), upper = float('inf')):
if not node:
return True
val = node.val
if val <= lower or val >= upper:
return False
if not helper(node.right, val, upper):
return False
if not helper(node.left, lower, val):
return False
return True
return helper(root)
700. 二叉搜索树中的搜索
给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。例如,
于是,我们对原始框架进行改造,抽象出一套针对 BST 的遍历框架:
boolean isInBST(TreeNode root, int target) {
if (root == null) return false;
if (root.val == target)
return true;
if (root.val < target)
return isInBST(root.right, target);
if (root.val > target)
return isInBST(root.left, target);
// root 该做的事做完了,顺带把框架也完成了,妙
}
# 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 searchBST(self, root: TreeNode, val: int) -> TreeNode:
if not root: #如果为空,直接pass
return None
if root.val == val: #如果等于目标值,返回该结点
return root
elif root.val >val: #大于目标值,搜索左子树
return self.searchBST(root.left,val)
else: #小于目标值,搜索右子树
return self.searchBST(root.right,val)
701. 二叉搜索树中的插入操作
给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
class Solution:
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
if not root:
return TreeNode(val)
if val < root.val:
root.left = self.insertIntoBST(root.left, val)
else:
root.right = self.insertIntoBST(root.right, val)
return root
450. 删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
说明: 要求算法时间复杂度为 O(h),h 为树的高度。
# 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 deleteNode(self, root: TreeNode, key: int) -> TreeNode:
def getMin(node: TreeNode):
# BST 最左边的就是最小的
while node.left != None:
node = node.left
return node
if root == None:
return None
if root.val == key:
# 这两个 if 把情况 1 和 2 都正确处理了
if root.left == None:
return root.right
if root.right == None:
return root.left
# 处理情况 3
minNode = getMin(root.right)
root.val = minNode.val
root.right = self.deleteNode(root.right, minNode.val)
elif root.val > key:
root.left = self.deleteNode(root.left, key)
else:
root.right = self.deleteNode(root.right, key)
return root
剑指 Offer 33. 二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:
5
/ \
2 6
/ \
1 3
示例 1:
输入: [1,6,3,2,5]
输出: false
示例 2:
输入: [1,3,2,6,5]
输出: true
class Solution:
def verifyPostorder(self, postorder: [int]) -> bool:
def recur(i, j):
if i >= j: return True
p = i
while postorder[p] < postorder[j]: p += 1
m = p
while postorder[p] > postorder[j]: p += 1
return p == j and recur(i, m - 1) and recur(m, j - 1)
return recur(0, len(postorder) - 1)
剑指 Offer 36. 二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
class Solution:
def treeToDoublyList(self, root: 'Node') -> 'Node':
def dfs(cur):
if not cur: return
dfs(cur.left) # 递归左子树
if self.pre: # 修改节点引用
self.pre.right, cur.left = cur, self.pre
else: # 记录头节点
self.head = cur
self.pre = cur # 保存 cur
dfs(cur.right) # 递归右子树
if not root: return
self.pre = None
dfs(root)
self.head.left, self.pre.right = self.pre, self.head
return self.head
235. 二叉搜索树的最近公共祖先
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 输出: 6 解释: 节点2
和节点8
的最近公共祖先是6。
示例 2
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 输出: 2 解释: 节点2
和节点4
的最近公共祖先是2
, 因为根据定义最近公共祖先节点可以为节点本身。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root.val < p.val and root.val < q.val:
return self.lowestCommonAncestor(root.right, p, q)
if root.val > p.val and root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
return root
236. 二叉树的最近公共祖先
剑指 Offer 68 - II. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/solution/236-er-cha-shu-de-zui-jin-gong-gong-zu-xian-hou-xu/
https://mp.weixin.qq.com/s?__biz=MzAxODQxMDM0Mw==&mid=2247485561&idx=1&sn=a394ba978283819da1eb34a256f6915b&chksm=9bd7f671aca07f6722f0bc1e946ca771a0a40fd8173cc1227a7e0eabfe4e2fcc57b9ba464547&scene=21#wechat_redirect
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root or root == p or root == q: return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if not left and not right: return # 1.
if not left: return right # 3.
if not right: return left # 4.
return root # 2. if left and right
95. 不同的二叉搜索树 II 科学刷题回溯法涉及
难度中等756
给定一个整数 n,生成所有由 1 ... n 为节点所组成的 二叉搜索树 。
示例:
输入:3
输出:
[
[1,null,3,2],
[3,2,null,1],
[3,1,null,null,2],
[2,1,3],
[1,null,2,null,3]
]
解释:
以上的输出对应以下 5 种不同结构的二叉搜索树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
96. 不同的二叉搜索树
难度中等956
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
示例:
输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3