目錄
104. 二叉樹的最大深度
https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
給定一個二叉樹,找出其最大深度。二叉樹的深度爲根節點到最遠葉子節點的最長路徑上的節點數。說明: 葉子節點是指沒有子節點的節點。
示例:給定二叉樹 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
題解
一:maxDepth返回以root爲根的二叉樹的最大深度。
class Solution(object):
def maxDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:
return 0
return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1
class Solution(object):
def maxDepth(self, root):
if not root:
return 0
return self._max_depth(root)
# return:以root爲根的樹的最大深度
def _max_depth(self, root):
if not root:
return 0
return max(self._max_depth(root.left), self._max_depth(root.right)) + 1
111. 二叉樹的最小深度
https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/
給定一個二叉樹,找出其最小深度。最小深度是從根節點到最近葉子節點的最短路徑上的節點數量。說明: 葉子節點是指沒有子節點的節點。
示例:給定二叉樹 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最小深度 2.
題解
minDepth返回以root爲根的最小深度,注意與104題的區別,這邊要注意例如下面這種情況,樹的最大深度是2,最小深度也是2,若依錯誤的寫法,最小深度則是1,因爲將1的右子樹傳入,則返回0,因此最終結果是1,但是我們發現1的左子樹還是有值的,故不可這麼做,那麼若左子樹爲空,得看右子樹;同理右子樹爲空得看左子樹;都不爲空,二者取最小:
[1,2]
1
/
2
class Solution(object):
def minDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:
return 0
# if not root.left and not root.right:
# return 1
elif not root.left:
return self.minDepth(root.right) + 1
elif not root.right:
return self.minDepth(root.left) + 1
else:
return min(self.minDepth(root.left), self.minDepth(root.right)) + 1
下面這種解法是錯誤的
class Solution(object):
def minDepth(self, root):
if not root:
return 0
return min(self.minDepth(root.left), self.minDepth(root.right)) + 1
226. 翻轉二叉樹
https://leetcode-cn.com/problems/invert-binary-tree/
翻轉一棵二叉樹。
示例:
輸入:
4
/ \
2 7
/ \ / \
1 3 6 9
輸出:
4
/ \
7 2
/ \ / \
9 6 3 1
題解
一:invertTree返回翻轉後的二叉樹的根(翻轉以root爲根的二叉樹,並將新的二叉樹的根返回 )。
class Solution(object):
def invertTree(self, root):
"""
:type root: TreeNode
:rtype: TreeNode
"""
if not root:
return root
left = self.invertTree(root.right)
right = self.invertTree(root.left)
# 此時若有一個子樹爲空,另一個不爲空,例如左子樹有值,右子樹爲空
# 翻轉後,將root的左節點重新指向翻轉後的右子樹(None)
# 翻轉後,將root的右節點重新指向翻轉後的左子樹
root.left, root.right = left, right
return root
100. 相同的樹
https://leetcode-cn.com/problems/same-tree/
給定兩個二叉樹,編寫一個函數來檢驗它們是否相同。如果兩個樹在結構上相同,並且節點具有相同的值,則認爲它們是相同的。
示例 1:
輸入: 1 1
/ \ / \
2 3 2 3
[1,2,3], [1,2,3]
輸出: true
示例 2:
輸入: 1 1
/ \
2 2
[1,2], [1,null,2]
輸出: false
示例 3:
輸入: 1 1
/ \ / \
2 1 1 2
[1,2,1], [1,1,2]
輸出: false
題解
一:isSameTree返回以p和q爲根的子樹是否相同。
class Solution(object):
def isSameTree(self, p, q):
"""
:type p: TreeNode
:type q: TreeNode
:rtype: bool
"""
if not p and not q:
return True
if (not p and q) or (not q and p) or p.val != q.val:
return False
return self.isSameTree(p.left, q.left) and self.isSameTree(q.right, p.right)
102. 二叉樹的層序遍歷
https://leetcode-cn.com/problems/binary-tree-level-order-traversal/
給你一個二叉樹,請你返回其按 層序遍歷 得到的節點值。 (即逐層地,從左到右訪問所有節點)。
示例:二叉樹:[3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其層次遍歷結果:
[
[3],
[9,20],
[15,7]
]
題解
一:層序遍歷。雙端隊列,此處應該先進先出,故每次向隊尾(append)添加元素,從隊首(popleft)移除元素。
from collections import deque
class Solution(object):
def levelOrder(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
if not root:
return []
q, res = deque(), []
q.append(root)
while q:
n = len(q)
res.append([])
for i in range(n):
node = q.popleft()
res[-1].append(node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
return res
from Queue import Queue
class Solution(object):
def levelOrder(self, root):
res = []
if not root:
return res
rec = Queue()
rec.put(root)
while not rec.empty():
tmp, n = [], rec.qsize()
while n > 0:
node = rec.get()
if node.left:
rec.put(node.left)
if node.right:
rec.put(node.right)
tmp.append(node.val)
n -= 1
res.append(tmp[:])
return res
101. 對稱二叉樹
https://leetcode-cn.com/problems/symmetric-tree/
給定一個二叉樹,檢查它是否是鏡像對稱的。
例如,二叉樹 [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
進階:你可以運用遞歸和迭代兩種方法解決這個問題嗎?
題解
一:遞歸,以root爲根的二叉樹是否對稱。轉化成兩個子樹是否對稱,即它們的兩個根結點具有相同的值,每個樹的右子樹都與另一個樹的左子樹鏡像對稱。時間複雜度:O(n),因爲我們遍歷整個輸入樹一次,所以總的運行時間爲 O(n),其中 n是樹中結點的總數。
class Solution(object):
# 以root爲根的二叉樹是否對稱
# 左子樹的右孩子=右子樹的左孩子
# 左子樹的左孩子=右子樹的右孩子
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
if not root:
return True
return self._isSymmetric(root.left, root.right)
# 以left和right爲根的二叉樹是否對稱
def _isSymmetric(self, left, right):
if not left and not right:
return True
if (not left and right) or (not right and left) or (left.val != right.val):
return False
return (self._isSymmetric(left.right, right.left) and self._isSymmetric(left.left, right.right))
二:借鑑102題層序遍歷的思路,每次取出一層之後看是否是鏡像,當然下層中的None也要記錄,不過下層爲None,就沒必要入隊了,因爲一旦上層形狀給定,下層的形狀(記錄過None的)也唯一給定。
from collections import deque
class Solution(object):
def isSymmetric(self, root):
if not root or (not root.left and not root.right):
return True
if (not root.left and root.right) or (root.left and not root.right):
return False
q = deque()
q.append(root)
while q:
n = len(q)
rec = []
for i in range(n):
node = q.popleft()
if node.left:
q.append(node.left)
rec.append(node.left.val)
else:
rec.append(None)
if node.right:
q.append(node.right)
rec.append(node.right.val)
else:
rec.append(None)
# print(rec)
l, r = 0, len(rec) - 1
while l < r:
if rec[l] != rec[r]:
return False
l += 1
r -= 1
return True
三:copy官方題解,https://leetcode-cn.com/problems/symmetric-tree/solution/dui-cheng-er-cha-shu-by-leetcode/,除了遞歸的方法外,我們也可以利用隊列進行迭代。隊列中每兩個連續的結點應該是相等的,而且它們的子樹互爲鏡像。最初,隊列中包含的是 root的左子樹 以及 root的右子樹。該算法的工作原理類似於 BFS,但存在一些關鍵差異。每次提取兩個結點並比較它們的值。然後,將兩個結點的左右子結點按相反的順序插入隊列中。當隊列爲空時,或者我們檢測到樹不對稱(即從隊列中取出兩個不相等的連續結點)時,該算法結束。
from collections import deque
class Solution(object):
def isSymmetric(self, root):
if not root or (not root.left and not root.right):
return True
if (not root.left and root.right) or (root.left and not root.right):
return False
q = deque()
q.append(root.left)
q.append(root.right)
while q:
l, r = q.popleft(), q.popleft()
if not l and not r:
continue
if (not l and r) or (l and not r) or (l.val != r.val):
return False
q.append(l.left)
q.append(r.right)
q.append(l.right)
q.append(r.left)
return True
222. 完全二叉樹的節點個數
給出一個完全二叉樹,求出該樹的節點個數。說明:完全二叉樹的定義如下:在完全二叉樹中,除了最底層節點可能沒填滿外,其餘每層節點數都達到最大值,並且最下面一層的節點都集中在該層最左邊的若干位置。若最底層爲第 h 層,則該層包含 1~ 2h 個節點。
示例:
輸入:
1
/ \
2 3
/ \ /
4 5 6
輸出: 6
題解
一:暴力求解,將每個節點都遍歷一遍,O(n)的時間複雜度。
class Solution(object):
def countNodes(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:
return 0
return self.countNodes(root.left) + self.countNodes(root.right) + 1
二:借鑑官方題解https://leetcode-cn.com/problems/count-complete-tree-nodes/solution/wan-quan-er-cha-shu-de-jie-dian-ge-shu-by-leetcode/,求出樹的最大深度d,因爲完全二叉樹,則非葉子 節點的個數,然後關鍵是求出葉子節點的個數。
現在有兩個問題:最後一層我們需要檢查多少個節點?一次檢查的最佳的時間性能是什麼?
讓我們從第一個問題開始思考。最後一層的葉子節點全部靠向左邊,我們可以用二分搜索只檢查 個葉子代替檢查全部葉子。讓我們思考第二個問題,最後一層的葉子節點索引在之間。如何檢查第 idx 節點是否存在?讓我們來用二分搜索來構造從根節點到 idx 的移動序列。如,idx = 4。idx 位於 0,1,2,3,4,5,6,7 的後半部分,因此第一步是向右移動;然後 idx 位於 4,5,6,7 的前半部分,因此第二部是向左移動;idx 位於 4,5 的前半部分,因此下一步是向左移動。一次檢查的時間複雜度爲 。我們需要 次檢查,一次檢查需要,所以總的時間複雜度爲。
class Solution(object):
# 深度 + 葉子節點的個數
def countNodes(self, root):
if not root:
return 0
d = self.depth(root)
if d == 1:
return 1
non_leaf_nodes = 2 ** (d - 1) - 1
l, r = 0, 2 ** (d - 1) - 1
while l <= r:
pivot = l + (r - l) // 2
if self.exists(pivot , d, root):
l = pivot + 1
else:
r = pivot - 1
return non_leaf_nodes + l
def depth(self, node):
d = 1
while node.left:
d += 1
node = node.left
return d
def exists(self, idx, d, node):
l, r = 0, 2 ** (d - 1) - 1
for _ in range(d - 1):
pivot = l + (r - l) // 2
if idx <= pivot:
node = node.left
r = pivot
else:
node = node.right
l = pivot + 1
return node is not None
110. 平衡二叉樹
https://leetcode-cn.com/problems/balanced-binary-tree/
給定一個二叉樹,判斷它是否是高度平衡的二叉樹。本題中,一棵高度平衡二叉樹定義爲:一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過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 。
題解
一:暴力解法,遍歷二叉樹中的每個節點,查看該節點的左右子樹的最大深度相差是否不超過1。若近乎平衡時間複雜度,對於每個深度爲 d 的節點 p,_maxDepth被調用(即)次。如果樹是傾斜的,算法沒有儘早結束,最終會達到 的複雜度。
class Solution(object):
def isBalanced(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
if not root:
return True
if abs(self._maxDepth(root.left) - self._maxDepth(root.right)) > 1:
return False
return self.isBalanced(root.left) and self.isBalanced(root.right)
def _maxDepth(self, node):
if not node:
return 0
return max(self._maxDepth(node.left), self._maxDepth(node.right)) + 1
二:提前終止,時間複雜度爲 O(N)。
class Solution(object):
def isBalanced(self, root):
if not root:
return True
return self._helper(root) != -1
def _helper(self, node):
if not node:
return 0
left_depth = self._helper(node.left)
if left_depth == -1:
return -1
right_depth = self._helper(node.right)
if right_depth == -1:
return -1
if abs(left_depth - right_depth) <= 1:
return max(left_depth, right_depth) + 1
return -1
112. 路徑總和
https://leetcode-cn.com/problems/path-sum/
給定一個二叉樹和一個目標和,判斷該樹中是否存在根節點到葉子節點的路徑,這條路徑上所有節點值相加等於目標和。
說明: 葉子節點是指沒有子節點的節點。
示例:
給定如下二叉樹,以及目標和 sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
返回 true, 因爲存在目標和爲 22 的根節點到葉子節點的路徑 5->4->11->2。
題解
一:葉子節點判斷,要保證葉子節點的合理性,需要先判斷該節點是否爲空
class Solution(object):
def hasPathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: bool
"""
if not root:
return False
if not root.left and not root.right and sum - root.val == 0:
return True
return self.hasPathSum(root.left, sum - root.val) or self.hasPathSum(root.right, sum - root.val)
404. 左葉子之和
https://leetcode-cn.com/problems/sum-of-left-leaves/
計算給定二叉樹的所有左葉子之和。
示例:
3
/ \
9 20
/ \
15 7
在這個二叉樹中,有兩個左葉子,分別是 9 和 15,所以返回 24
題解
一:純粹的遞歸。
class Solution(object):
def sumOfLeftLeaves(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:
return 0
left_leaf = 0
if root.left and not root.left.right and not root.left.left:
left_leaf = root.left.val
return self.sumOfLeftLeaves(root.left) + self.sumOfLeftLeaves(root.right) + left_leaf