目录
注意
主要和b站大雪菜一起刷题,宝藏up主(https://www.bilibili.com/video/BV19t411w7Ep/?spm_id_from=333.788.videocard.0)
98. 验证二叉搜索树
思路:
- 这个题只需要判断是否是BST即可
- 题目条件限制的也很清晰,不会出现节点相等的情况
- 考虑划分范围的做法,假如当前节点的值为x,则左子树的取值范围为[-∞,x-1],右子树的取值范围为[x+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 isValidBST(self, root: TreeNode) -> bool:
return self.dfs(root, -float('INF'), float('INF'))
def dfs(self, root, min_val, max_val):
if not root:
return True
if root.val>max_val or root.val<min_val:
return False
return self.dfs(root.left, min_val, root.val-1) and self.dfs(root.right, root.val+1, max_val)
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]:
# 开栈
stack = []
# 结果
res = []
# 遍历指针
p = root
# 当没有遍历完或者栈不为空时
while p or stack:
# 左节点入栈
while p:
stack.append(p)
p = p.left
# 出栈
p = stack.pop()
res.append(p.val)
p = p.right
return res
101. 对称二叉树
思路:
- 递归来看:①根节点要相等②左边的左子树和右边的右子树相等②左边的右子树和右边的左子树相等
- 迭代来看:①左边看:左中右查看②右边看:右中左查看,对比值是否相等(和迭代中序遍历一样的思路)
递归版:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
return self.dfs(root.left, root.right)
def dfs(self, l, r):
if not l or not r:
return not l and not r
return l.val == r.val and self.dfs(l.left, r.right) and self.dfs(l.right,r.left)
迭代版:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
# 为空
if not root:
return True
stack1, stack2 = [], []
p, q = root.left, root.right
while p or q or stack1 or stack2:
while q and p:
stack1.append(p)
p = p.left
stack2.append(q)
q = q.right
if p or q:
return False
p = stack1.pop()
q = stack2.pop()
if p.val != q.val:
return False
p = p.right
q = q.left
return True
105. 从前序与中序遍历序列构造二叉树
思路:
- 这类题的思路其实差不多,以preorder = [3,9,20,15,7],inorder = [9,3,15,20,7]为例。preorder第一个出现的是根节点,找到其在inorder的位置p,则p左边是属于左子树,p右边属于右子树。递归的再在左子树、右子树的部分重复上述过程即可。
# 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, preorder: List[int], inorder: List[int]) -> TreeNode:
# 存储数字在inorder中的下标
pos = {}
for index, num in enumerate(inorder):
pos[num] = index
# 二叉树节点个数
n = len(preorder)
return self.dfs(preorder, inorder, pos, 0, n-1, 0, n-1)
def dfs(self, preorder, inorder, pos, pl, pr, il, ir):
# 已经建立完
if pl > pr:
return
# 取出根节点
val = preorder[pl]
# 获得在inorder中的下标
p = pos[val]
# 左子树个数
len_ = p - il
# 建立新节点
root = TreeNode(val)
root.left = self.dfs(preorder, inorder, pos, pl+1, pl+len_, il, p-1)
root.right = self.dfs(preorder, inorder, pos, pl+len_+1, pr, p+1, ir)
return root
102. 二叉树的层序遍历
思路:
- BFS,以层为单位做
- 注意python列表传递值的时候需要[:]
# 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]]:
if not root:
return []
# 存储当前层的节点
cur = [root]
# 存储下一层的节点
next_node = []
# 存储当前层的结果
cur_res = []
# 存储最终结果
res = []
while cur:
# 取出当前层的节点
x = cur.pop(0)
if x.left:# 有左孩子就放入下一层
next_node.append(x.left)
if x.right:# 有右孩子就放入下一层
next_node.append(x.right)
cur_res.append(x.val)
# 当前层遍历完
if not cur:
cur = next_node[:]
res.append(cur_res[:])
next_node.clear()
cur_res.clear()
return res
236. 二叉树的最近公共祖先
思路:
- 这是一个递归的思路,如果当前root为根的子树中包含了p和q,则返回最近共公共祖先
- 如果只包含了p,则返回p
- 如果只包含了q,则返回q
- 如果都不包含则返回null
- 如果p、q在异侧,返回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 lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root or root==p or root==q:
# 若根节点为空或者根节点就是p、q
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if not left:
# p、q不在左子树中
return right
if not right:
# p、q不在右子树中
return left
return root
543. 二叉树的直径
思路:
- 二叉树的直径是指最长的路径
- 枚举树中的所有最高点
- 经过当前点的最长路径即其左子树的最长路径+右子树的最长路径
- 递归时需要计算,从当前节点往下走,深度的最大值
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.res = 0
def diameterOfBinaryTree(self, root: TreeNode) -> int:
if not root:
return 0
self.dfs(root)
return self.res
def dfs(self, root):
if not root:
return 0
left = self.dfs(root.left)
right = self.dfs(root.right)
self.res = max(self.res, left+right)
return max(left, right)+1
124. 二叉树中的最大路径和
思路:
- 枚举最高点
- 向左走,当前val+L
- 向右走,当前val+R
- 不走
- 三种情况取最大值,向上返回的时候,若是负值其实已经没有必要返回
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.res = -float('inf')
def maxPathSum(self, root: TreeNode) -> int:
self.dfs(root)
return self.res
def dfs(self, root):
# 返回当前root向下走最大权值
if not root:
return 0
left = self.dfs(root.left)
right = self.dfs(root.right)
self.res = max(self.res, left+right+root.val)
return max(0, root.val+max(left, right))
173. 二叉搜索树迭代器
思路:
- 由于是要使用O(h)的内存,所以是跟树高相关,若是直接进行一个中序遍历的话,则会使用O(n)的内存,即节点个数。所以首先考虑栈的方式。
- 利用栈存储中序遍历的结果,栈顶就一直放的是最小的那个
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class BSTIterator:
def __init__(self, root: TreeNode):
self.stk = []
p = root
while p:
self.stk.append(p)
p = p.left
def next(self) -> int:
"""
@return the next smallest number
"""
p = self.stk.pop()
res = p.val
p = p.right
while p:
self.stk.append(p)
p = p.left
return res
def hasNext(self) -> bool:
"""
@return whether we have a next smallest number
"""
if self.stk:
return True
else:
return False
# Your BSTIterator object will be instantiated and called as such:
# obj = BSTIterator(root)
# param_1 = obj.next()
# param_2 = obj.hasNext()
297. 二叉树的序列化与反序列化
思路:
- 主要需要考虑如何序列化,并且反序列化如何处理。
- 这里使用的是前序遍历序列化、反序列化
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Codec:
def serialize(self, root):
"""Encodes a tree to a single string.
:type root: TreeNode
:rtype: str
"""
return self.dfs1(root, "")
def dfs1(self, root, s):
if not root:
s += '#,'
else:
s += str(root.val) + ","
s = self.dfs1(root.left, s)
s = self.dfs1(root.right, s)
return s
def deserialize(self, data):
"""Decodes your encoded data to tree.
:type data: str
:rtype: TreeNode
"""
li = data.split(",")
return self.dfs2(li)
def dfs2(self, li):
if not li:
return
if li[0] == "#":
li.pop(0)
return None
else:
root = TreeNode(int(li[0]))
li.pop(0)
root.left = self.dfs2(li)
root.right = self.dfs2(li)
return root
# Your Codec object will be instantiated and called as such:
# codec = Codec()
# codec.deserialize(codec.serialize(root))