目錄
注意
主要和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))