1. 二叉树的层序遍历
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7]
,
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
方法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 levelOrder(self, root: TreeNode) -> List[List[int]]:
# 层序遍历 按层访问
# 队列 FIFO
queue_node = [root]
node_list = []
while queue_node: # 队列非null, 一直循环
# 处理 根节点
queue_len = len(queue_node)
print(queue_len)
layer_queue = []
layer_list = []
for node in queue_node:
if node:
layer_list.append(node.val) # 没有按照队列操作,每层输出
layer_queue.append(node.left)
layer_queue.append(node.right)
if layer_list:
node_list.append(layer_list)
queue_node = layer_queue
return node_list
方法2: 使用一个depth标记
# 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]]:
# 层序遍历 按层访问
# 队列 FIFO
queue_node = [(root, 0)] # 深度
cur_depth = 0 # 用来 确定是否换层
ans = []
temp = []
for node, depth in queue_node:
if node:
# 判断 深度是否发生变化
if cur_depth != depth:
cur_depth = depth
ans.append(temp)
temp = []
temp.append(node.val)
queue_node.append((node.left, depth+1))
queue_node.append((node.right, depth+1)) # 子节点 所以深度+1
if temp:
ans.append(temp)
return ans
给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回锯齿形层次遍历如下:
[
[3],
[20,9],
[15,7]
]
方法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 zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
queue_node = [root]
node_list = []
flag = False # 为True 将每层node值结果倒序
# 思路:保持层序遍历不变, 只在 需要从右到左时: 每层节点node值 倒序一下即可
while queue_node:
layer_list = []
layer_node = []
for node in queue_node:
if node:
layer_list.append(node.val)
layer_node.append(node.left)
layer_node.append(node.right)
if flag:
layer_list.reverse()
flag = not flag
if layer_list:
node_list.append(layer_list)
queue_node = layer_node
return node_list
3. 94. 二叉树的中序遍历
给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [1,3,2]
方法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 inorderTraversal(self, root: TreeNode) -> List[int]:
# 1.递归 中序遍历
if root:
left = self.inorderTraversal(root.left)
middle = left + [root.val]
right = self.inorderTraversal(root.right)
return middle + right
return []
方法2: 迭代
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
# 2.迭代算法
value_list = []
p = root # p 当作移动指针
stack = [] #栈:先进后出, # 队列:先进先出;
while p or stack:
while p: # 找左子树 一直找下去
stack.append(p)
p = p.left # p 移动 到 左孩子,直到为null
# p 为null,从stack中pop
p = stack.pop()
value_list.append(p.val)
# 处理右自子树
p = p.right
return value_list
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true
,否则返回 false
。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:
5
/ \
2 6
/ \
1 3
示例 1:
输入: [1,6,3,2,5]
输出: false
示例 2:
输入: [1,3,2,6,5]
输出: true
解法1:
class Solution:
def verifyPostorder(self, postorder: List[int]) -> bool:
'''
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树 也分别为二叉排序树。
'''
'方法1: 递归'
if len(postorder) <= 2:
return True
'后序遍历结果规律: 最后一个为根结点, 从左到右遍历,找到第一个大于 根结点的值(索引:k) '
'左子树在:[0, k-1], 右子树在: [k, right-1], 即可递归'
'判断条件:若满足左子树值都小于根结点, 右子树值都大于根节点, 为True'
def verify(tree_list, left, right):
# 递归必须 🈶️结束条件
if left >= right:
return True
root = tree_list[right]
# 寻找 第一个大于 root的 值
k = left
while k < right and tree_list[k] < root:
k = k + 1
# 判断
index = k
while index < right:
if tree_list[index] < root: # 如果右子树中 出现大于 根结点的 则 返回false
return False
index = index + 1
if not verify(tree_list, left, k-1): # 遍历左子树
return False
if not verify(tree_list, k, right-1): # 遍历右子树
return False
return True # 左右子树 都没有问题 才是 正确的
return verify(postorder, 0, len(postorder)-1)
5. 合并二叉树
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
示例 1:
输入:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
输出:
合并后的树:
3
/ \
4 5
/ \ \
5 4 7
解法1: 递归
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode:
new_tree = None
if t1 and t2: # 都不为null, 则 根节点相加
new_tree = TreeNode(t1.val + t2.val)
# 合并左子树
if t1 and not t2:
new_tree = t1
if not t1 and t2:
new_tree = t2
if t1 and t2: # 都不为null,才 继续遍历
new_tree.left = self.mergeTrees(t1.left, t2.left)
new_tree.right = self.mergeTrees(t1.right, t2.right)
return new_tree
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
解法1:
# class TreeNode: # 这一段必须注释掉,否则 输出一直为null
# 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:
if not inorder:
return None
root_node = postorder[-1] # 根结点
root_tree = TreeNode(root_node)
index = inorder.index(root_node)
zuo = inorder[:index]
right = inorder[index+1:]
zuo_post = postorder[:index]
right_post = postorder[index:-1]
if zuo:
root_tree.left = self.buildTree(zuo, zuo_post)
if right:
root_tree.right = self.buildTree(right, right_post)
return root_tree
给定一个二叉树
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
进阶:
你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
示例:
输入:root = [1,2,3,4,5,null,7]
输出:[1,#,2,3,#,4,5,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。
解法1:
"""
# 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':
# 层序遍历
layer_node = [root]
while layer_node:
length = len(layer_node)
nodes = []
for i in range(0, length - 1):
layer_node[i].next = layer_node[i+1]
if layer_node[i].left: # 每层的都添加进去
nodes.append(layer_node[i].left)
if layer_node[i].right:
nodes.append(layer_node[i].right)
# 切记 节点也可能为null
if layer_node[length-1] and layer_node[length-1].left:
nodes.append(layer_node[length-1].left)
if layer_node[length-1] and layer_node[length-1].right:
nodes.append(layer_node[length-1].right)
layer_node = nodes
return root
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
解法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 lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 二叉搜索树, 二叉排序树
if not root:
return None
if p.val <= root.val and q.val >= root.val:
return root
if p.val >= root.val and q.val <= root.val:
return root
# 这样 两个 值 在 根结点的 同一侧
# 同一侧 第一个相等的 肯定是 最近公共祖先。
# 先找 左子树
node = self.lowestCommonAncestor(root.left, p, q)
if not node:
node = self.lowestCommonAncestor(root.right, p, q)
return node
9. 113. 路径总和 II
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
# 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]]:
# 必须是 从 根结点 到 叶子节点 的 路径总和
all_node = [] # 设个全局变量
node_list = [] # 栈
def bianli(root, sum, node_sum): # 前序遍历
if not root:
return
node_list.append(root.val)
if not root.right and not root.left:
# 必须是叶子节点, 必须结束了
if sum == node_sum + root.val:
all_node.append(node_list.copy()) # 数组 必须copy一下, 不然全都改变了
return
if root.left:
bianli(root.left, sum, node_sum + root.val)
node_list.pop() # 后进先出 # 回溯
if root.right:
bianli(root.right, sum, node_sum + root.val)
node_list.pop() # 后进先出
return
bianli(root, sum, 0)
return all_node
10. 145. 二叉树的后序遍历
解法1: 递归解法
# 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 []
result = []
if root.left:
result += self.postorderTraversal(root.left)
if root.right:
result += self.postorderTraversal(root.right)
result.append(root.val)
return result
解法2: 非递归解法
11. 222. 完全二叉树的节点个数
给出一个完全二叉树,求出该树的节点个数。
说明:
完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
示例:
输入:
1
/ \
2 3
/ \ /
4 5 6
输出: 6
解法1: O(N)
class Solution:
def countNodes(self, root: TreeNode) -> int:
if not root:
return 0
return self.countNodes(root.left) + self.countNodes(root.right) + 1
解法2: O(N)
class Solution:
def countNodes(self, root: TreeNode) -> int:
# 层序 全遍历一遍 节点
nodes = [root]
count_node = 0
layer_node = []
while nodes:
for node in nodes:
if node:
count_node = count_node + 1
if node and node.left:
layer_node.append(node.left)
if node.right:
layer_node.append(node.right)
nodes = layer_node
layer_node = []
return count_node
解法3:
class Solution:
def countNodes(self, root: TreeNode) -> int:
if not root:
return 0
level = 0 # 计算有多少层
node = root
while node.left: # 计算最深层,
level += 1
node = node.left
low = 1<<level # 最后一层 上面的 所有节点数。
high = (1<<(level+1)) - 1
while low < high: # 二分查找
mid = (high - low + 1) // 2 + low # 要确定是否存在的 节点
if self.exists(root, level, mid): # 判断节点是否存在
low = mid
else:
high = mid - 1
return low
def exists(self, root, level, k):
# 确定路径, 使用k的二进制确定
k_2 = list(bin(k).split('b')[-1][1:]) #二进制 去除首位1, 剩余位为从根结点到节点的 路径, 1: 右子树,0:左子树
k_2 = k_2[::-1] #
node = root
while k_2 and node: # 相比于node and k_2 可以节约运行时间
if k_2.pop() == '1':
node = node.right
else:
node = node.left
return node != None
# def exists(self, root, level, k): # 看不太明白, 别人的 很正确的。
# bits = 1 << (level - 1) # 上一层
# node = root
# while node and bits > 0:
# if bits & k == 0: # 按路径查找
# node = node.left
# else:
# node = node.right
# bits >>= 1 # 右移1位
# return node != None
12. 剑指 Offer 27. 二叉树的镜像 【面试遇到了】
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
例如输入:
4
/ \
2 7
/ \ / \
1 3 6 9
镜像输出:
4
/ \
7 2
/ \ / \
9 6 3 1
限制:
0 <= 节点个数 <= 1000
解法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 mirrorTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
#temp = root.left
#root.left = self.mirrorTree(root.right)
#root.right = self.mirrorTree(temp)
root.left, root.right = self.mirrorTree(root.right), self.mirrorTree(root.left)
return root
解法2: 辅助栈或队列
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
# 辅助栈或队列;
zhan = [root]
while zhan:
node = zhan.pop()
if not node:
continue
if node.left:
zhan.append(node.left)
if node.right:
zhan.append(node.right)
node.left, node.right = node.right, node.left
return root
13. 236. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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。因为根据定义最近公共祖先节点可以为节点本身。
说明:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉树中。
解法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 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:
return right
if not right:
return left
return root # 要先说 思路的 递归,
14. 98. 验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:
2
/ \
1 3
输出: true
示例 2:
输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。
解法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 isValidBST(self, root: TreeNode) -> bool:
# 中序遍历结果是个 升序数组
ans = []
def zhong(root):
if not root:
return
zhong(root.left)
ans.append(root.val)
zhong(root.right)
zhong(root)
# 判断是否 升序排列
# print(ans)
first = ans[0]
for i in range(1, len(ans)):
if first < ans[i]: # 大于 (不包括等于)
first = ans[i]
else:
return False
return True
解法2: 递归, 判断条件
# 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:
# 递归, 利用 左子树 小于根结点, 右子树大于根结点, 来判断 是否符合
def valid(root, lower=float('-inf'), upper=float('inf')):
if not root: # 空节点为True;
return True
# 不为bst则返回False, 为bst接着验证左右子树
if not lower < root.val < upper: # 判断依据
return False
if not valid(root.left, lower, root.val):
return False
if not valid(root.right, root.val, upper):
return False
return True # 左右子树都为bst,则返回true
return valid(root) # 刚开始时,是无限小,无限大 [-inf, inf]
解法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 isValidBST(self, root: TreeNode) -> bool:
global pre
pre = float('-inf') # pre 必须是全局才行
def middleorder(root):
if not root:
return True
if not middleorder(root.left):
return False
global pre
if root.val <= pre: # 小于等于 false
return False
pre = root.val
return middleorder(root.right)
return middleorder(root)
15. 662. 二叉树最大宽度
给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(full binary tree)结构相同,但一些节点为空。
每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度
示例 1:
输入:
1
/ \
3 2
/ \ \
5 3 9
输出: 4
解释: 最大值出现在树的第 3 层,宽度为 4 (5,3,null,9)。
解法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 widthOfBinaryTree(self, root: TreeNode) -> int:
# 宽度优先搜索; 给每个节点 一个 深度 和 pos ;
queue = [(root, 0, 0)]
cur_depth = left = ans = 0
for node, depth, pos in queue:
if node:
queue.append((node.left, depth+1, pos*2))
queue.append((node.right, depth+1, pos*2 + 1))
if cur_depth != depth: # 移动到下层了, 改变left 和深度
cur_depth = depth
left = pos
ans = max(pos - left + 1, ans)
return ans