0. 總結
二叉樹的核心就是用遞歸的思想解決問題,三個要素分析清楚:
- 尋求遞歸的子問題,子問題就是要解決的問題落實到一個(帶左右孩子的)節點上時應該怎麼做;
- 遞歸終止條件;
- 遞歸返回值;
1. 合併二叉樹
# 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 mergeTrees(self, t1, t2):
"""
:type t1: TreeNode
:type t2: TreeNode
:rtype: TreeNode
"""
if t1 is None:
return t2
if t2 is None:
return t1
t1.val += t2.val
t1.left = self.mergeTrees(t1.left, t2.left)
t1.right = self.mergeTrees(t1.right, t2.right)
return t1
2. 翻轉二叉樹
# 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 invertTree(self, root):
"""
:type root: TreeNode
:rtype: TreeNode
"""
if root is None:
return None
root.left, root.right = root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)
return root
3. 二叉樹的最大深度
104. maximum-depth-of-binary-tree
# 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 maxDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if root is None:
return 0
return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))
4. 把二叉搜索樹轉換爲累加樹
538. convert-bst-to-greater-tree
# 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 __init__(self):
self.acc = 0
def convertBST(self, root):
"""
:type root: TreeNode
:rtype: TreeNode
二叉樹遍歷:右 根 左
"""
if root is None:
return None
self.convertBST(root.right)
root.val += self.acc
self.acc = root.val
self.convertBST(root.left)
return root
5. 對稱二叉樹
# 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 isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
笨辦法
分別 根左右、根右左 遍歷這棵樹,比較生成的元素是否一一相等
(注意遍歷的時候None也要考慮進去)
聰明辦法
兩個指針指向同一棵樹,同步移動,一個向左、一個向右,檢查是否相等
"""
def check_node(t1, t2):
if not t1 and not t2:
return True
if not t1 or not t2:
return False
return t1.val == t2.val and check_node(t1.left, t2.right) and check_node(t1.right, t2.left)
return check_node(root, root)
6. 二叉樹的直徑
# 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 __init__(self):
self.max_path_len = 0
def diameterOfBinaryTree(self, root):
"""
:type root: TreeNode
:rtype: int
解法
任意兩節點的路徑都可以表示爲 以某個節點爲根的左右子樹深度之和
最長直徑,就是由 左右子樹深度之和最大的子樹(以任意節點爲根) 產生的
"""
# 笨辦法遞歸
# def max_depth(root):
# if not root:
# return 0
# return 1 + max(max_depth(root.left), max_depth(root.right))
# if not root:
# return 0
# path_len = max_depth(root.left) + max_depth(root.right)
# self.max_path_len = max(self.max_path_len, path_len)
# self.diameterOfBinaryTree(root.left)
# self.diameterOfBinaryTree(root.right)
# return self.max_path_len
# 在求數最大深度遞歸算法的基礎上增加求極值
def max_depth(root):
if not root:
return 0
l_depth = max_depth(root.left)
r_depth = max_depth(root.right)
self.max_path_len = max(self.max_path_len, l_depth+r_depth)
return 1 + max(l_depth, r_depth)
max_depth(root)
return self.max_path_len
7. 二叉樹的中序遍歷
94. binary-tree-inorder-traversal
# 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 inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
思路
遞歸算法簡單
非遞歸用循環和棧實現
"""
result = []
stack = []
node = root
while node or stack:
while node:
stack.append(node) # 左鏈入棧
node = node.left
node = stack.pop()
result.append(node.val) # 輸出
node = node.right # 右鏈
return result
8. 二叉樹展開爲鏈表
114. flatten-binary-tree-to-linked-list
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def flatten(self, root):
"""
:type root: TreeNode
:rtype: None Do not return anything, modify root in-place instead.
思路
先序遍歷二叉樹, 將結果保存到一個數組
迭代數組, 重鏈指針
或者使用後序遍歷, 直接在traverse內部重鏈, 需使用一個全局變量pre
"""
def traverse(root, array):
if not root:
return
array.append(root)
traverse(root.left, array)
traverse(root.right, array)
array = []
traverse(root, array)
for i in range(len(array)-1):
array[i].left = None
array[i].right = array[i+1]
9. 從前序與中序遍歷序列構造二叉樹
105. construct-binary-tree-from-preorder-and-inorder-traversal
# 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
思路
前序遍歷:[ 根節點, [左子樹的前序遍歷結果], [右子樹的前序遍歷結果] ]
中序遍歷:[ [左子樹的中序遍歷結果], 根節點, [右子樹的中序遍歷結果] ]
根據前序遍歷拿到根節點, 用根節點到中序遍歷結果find, 找到左子樹結果與右子樹結果分界點
遞歸對左右子樹, 以同樣的方式構建
"""
if not preorder or not inorder:
return None
node = TreeNode(preorder[0])
node_idx = inorder.index(preorder[0])
node.left = self.buildTree(preorder[1:node_idx+1], inorder[:node_idx])
node.right = self.buildTree(preorder[node_idx+1:], inorder[node_idx+1:])
return node
10. 不同的二叉搜索樹
96. unique-binary-search-trees
class Solution(object):
def numTrees(self, n):
"""
:type n: int
:rtype: int
思路
題目滿足卡塔蘭數, 請參考下面資料
https://baike.baidu.com/item/catalan/7605685?fr=aladdin
https://leetcode-cn.com/problems/unique-binary-search-trees/solution/bu-tong-de-er-cha-sou-suo-shu-by-leetcode/
"""
C = 1
for i in range(0, n):
C = C * 2*(2*i+1)/(i+2)
return int(C)
11. 二叉樹的最近公共祖先
236. lowest-common-ancestor-of-a-binary-tree
# 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 lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
思路
將每個節點的父節點存到一個字典裏面,
分別從p, q兩個節點往上走, 最先相遇的即是最近公共祖先
"""
def save_parents(root):
if not root:
return
if root.left:
parents[root.left] = root
if root.right:
parents[root.right] = root
save_parents(root.left)
save_parents(root.right)
def get_node_parents(node): # 獲取node的所有父親, 從近到遠, 包含自身
node_parents = [node]
while node in parents:
node_parents.append(parents[node])
node = parents[node]
return node_parents
parents = {}
save_parents(root)
p_parents, q_parents = get_node_parents(p), get_node_parents(q)
for i in range(min(len(p_parents), len(q_parents))): # p和q屬於不同子樹
if p_parents[-i-1] == q_parents[-i-1]:
continue
return p_parents[-i]
# p和q在同棵子樹
nearest_parent = p_parents[0] if len(p_parents) < len(q_parents) else q_parents[0]
return nearest_parent
12. 二叉樹的層序遍歷
102. binary-tree-level-order-traversal
# 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 levelOrder(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
思路
帶棧深度地遍歷二叉樹, 將節點按棧深保存到result
"""
def traverse(root, depth, result):
if not root:
return
if depth >= len(result):
result.append([])
result[depth].append(root.val)
traverse(root.left, depth+1, result)
traverse(root.right, depth+1, result)
result = []
traverse(root, 0, result)
return result
13. 路徑總和 III
# 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 __init__(self):
self.path_num = 0
def pathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: int
思路
兩重遞歸
1. 從根節點開始遍歷,計算滿足條件的路徑條數;(假設路徑一定從根節點開始)
2. 分別以所有節點爲根節點,計算路徑總條數;
"""
if root is None:
return 0
self.path(root, sum)
self.pathSum(root.left, sum)
self.pathSum(root.right, sum)
return self.path_num
def path(self, root, sum):
if root is None:
return
sum -= root.val
if sum == 0:
self.path_num += 1
self.path(root.left, sum)
self.path(root.right, sum)