Python 刷題筆記:二叉樹專題二

昨天接觸了二叉樹中的前中後三序遍歷的代碼實現,今天來看剩下的那種層序遍歷。

題目一

第 102 題:二叉樹的層序遍歷

難度:中等

給你一個二叉樹,請你返回其按 層序遍歷 得到的節點值。 (即逐層地,從左到右訪問所有節點)。

示例:

二叉樹:[3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其層次遍歷結果:

[
  [3],
  [9,20],
  [15,7]
]

題目分析

看其輸出格式,是將二叉樹每層的節點放到單獨的列表中,而代碼輸入的是 root 根節點,要通過 root.left 取左子節點、root.right 取其右節點。那麼可以每次都提取同一層的節點記錄在同一列表中,遍歷列表、取列表中節點的子節點,繼續將結果放入同一列表中,直到最後一層。

代碼實現

# 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 root!=None:
            level = [root]
        # 若根節點空,保持列表爲空,最終直接返回
        else:
            level = []
        # 用來記錄結果的列表
        result = []
        # 當層列表非空時
        while level:
        	# 將層列表中的節點值組成列表存入結果中
            result.append([ item.val for item in level if item!=None])
            # 新的層列表
            new_level = []
            # 遍歷當前層列表
            for node in level:
            	# 如果左子節點非空
                if node.left!=None:
                	# 將左子節點加入到新的層列表中
                    new_level.append(node.left)
                # 同理處理右子節點
                if node.right!=None:
                    new_level.append(node.right)
            # 將新的子節點賦給層列表,帶入下次循環
            level = new_level
        # 返回結果列表
        return result

提交測試表現:

執行用時 : 48 ms, 在所有 Python3 提交中擊敗了 37.30% 的用戶
內存消耗 : 14.1 MB, 在所有 Python3 提交中擊敗了 7.14% 的用戶

原本想參考題解優化的,後來發現題解中提到的“廣度優先搜索”方法下的代碼邏輯與我們的代碼基本相同。

廣度優先搜索算法(英語:Breadth-First Search,縮寫爲BFS),又譯作寬度優先搜索,或橫向優先搜索,是一種圖形搜索算法。簡單的說,BFS是從根節點開始,沿着樹的寬度遍歷樹的節點。如果所有節點均被訪問,則算法中止。
維基百科-廣度優先搜索

挺開心的,可以獨立做出二叉樹的題了!

題目二

面試題 檢查平衡性

難度:簡單

實現一個函數,檢查二叉樹是否平衡。在這個問題中,平衡樹的定義如下:任意一個節點,其兩棵子樹的高度差不超過 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#來源:力扣(LeetCode)
#鏈接:https://leetcode-cn.com/problems/check-balance-lcci

題目分析

這雖然標着個簡單題,考慮半天沒有頭緒,想着如果通過層序遍歷這二叉樹,給每層節點記錄高度,但越想就越複雜了。學習下題解裏的優秀解法吧!

這裏直接貼代碼來學習:

# 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.flag = True
    def isBalanced(self, root: TreeNode) -> bool:
		# 定義獲取節點高度的函數,之後遞歸調用
        def isb(root):
        	# 空節點,返回高度 0
            if not root:
                return 0
            # 由左子樹可計算出的高度=左子樹高度+1
            l = isb(root.left) + 1
            # 由右子樹計算的高度 = 右子樹高度+1
            r =  isb(root.right) + 1
            # 若左右子樹高度差大於1
            if abs(l-r)>1:
            	# 將全局的平衡狀態改爲 False
                self.flag = False
            # 返回左右計算的最大高度      
            return max(l,r)
        # 由根節點開始執行函數
        isb(root)
        # 返回最終的平衡狀態
        return self.flag 

#作者:skyyou-dang
#鏈接:https://leetcode-cn.com/problems/check-balance-lcci/solution/she-zhi-yi-ge-bian-liang-bao-cun-xia-mou-ge-jie-di/

原以爲會是比較簡單直接的計算高度方法,沒想到用到了遞歸,以及通過 init 中定義初始屬性實現了全局變量的作用。我嘗試着去掉這個 init 中對 flag 的定義與使用,換成函數內的變量會麻煩很多。對類、方法、屬性這些通過題目也有比較多接觸,之後也要專門系統整理下相關內容。

這個解法思路,贊,多消化消化。

題目三

第 226 題:翻轉二叉樹

難度:簡單

翻轉一棵二叉樹。

示例 1:
輸入:
     4
   /   \
  2     7
 / \   / \
1   3 6   9

示例 2:
輸出:
     4
   /   \
  7     2
 / \   / \
9   6 3   1

#來源:力扣(LeetCode)
#鏈接:https://leetcode-cn.com/problems/invert-binary-tree

題目分析

解法一:

看到這題,首先想到的還是遍歷每個節點,然後將其左右子節點對調就可以了。遍歷的過程還是用我們第一題裏設計的層級遍歷,應該就能一遍過。

代碼實現

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
		# 空節點單獨處理下        
        if root ==None:
            return None
		# 層列表
        level = [root]
        # 層列表不爲空,循環
        while level:
        	# 裝子節點的新列表
            new_level = []
            # 遍歷層列表中的節點
            for item in level:
            	# 對調左右子節點位置
                item.left,item.right = item.right,item.left
                # 若左子節點非空
                if item.left:
                	# 加入到新列表中
                    new_level.append(item.left)
                # 新列表添加非空右子節點
                if item.right:
                    new_level.append(item.right)
            # 層列表更新爲新記錄的子節點列表,進入下一層循環
            level = new_level
        # 對調完所有的,返回根節點
        return root

提交測試表現:

執行用時 : 36 ms, 在所有 Python3 提交中擊敗了 80.20% 的用戶
內存消耗 : 13.7 MB, 在所有 Python3 提交中擊敗了 5.26% 的用戶

解法二

難得發現一道可以自己壯着膽子用遞歸的題目,既然是要翻轉二叉樹,那麼翻轉子樹完全可以通過遞歸調用自身來實現,翻轉完兩子樹,再將兩子節點翻轉即可!

代碼一氣呵成:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
		# 空節點返回 None
        if root==None:
            return None
		# 遞歸翻轉左子樹
        self.invertTree(root.left)
        # 遞歸翻轉右子樹
        self.invertTree(root.right)
		# 交換左右子節點
        root.left, root.right = root.right,root.left
		# 返回根節點
        return root

提交測試表現:

執行用時 : 40 ms, 在所有 Python3 提交中擊敗了 61.62% 的用戶
內存消耗 : 13.7 MB, 在所有 Python3 提交中擊敗了 5.26% 的用戶

結論

今天遇到的二叉樹題目,要麼是基於層序遍歷,要麼是基於遞歸實現,做起來也有豁然開朗的感覺。

二叉樹初接觸可能會不知所云,慢慢摸索規律還是挺有意思的。加上昨天,我們練習了五道 LeetCode 關於二叉樹的題目(外加一道面試題目),明天先告一段落、繼續換個專題練習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章