LeetCode0429: N叉樹的層序遍歷

題目介紹

描述:

給定一個 N 叉樹,返回其節點值的層序遍歷。 (即從左到右,逐層遍歷)。

例如,給定一個 3叉樹 :

返回其層序遍歷:

[
     [1],
     [3,2,4],
     [5,6]
]

說明:

樹的深度不會超過 1000。
樹的節點總數不會超過 5000。

解題思路:

遞歸算法的關鍵是要明確函數的「定義」是什麼,然後相信這個定義,利用這個定義推導最終結果。

寫樹相關的算法,簡單說就是,先搞清楚當前 root 節點該做什麼,然後根據函數定義遞歸調用子節點,遞歸調用會讓孩子節點做相同的事情。

二叉樹題目的一個難點在於如何通過題目的要求思考出每一個節點需要做什麼

二叉樹解題策略

一 遞歸 二 隊列 + 迭代 (層次遍歷) 三 棧 + 迭代 (非遞歸遍歷) 四 其它

三種基本的遍歷方式,都可以用遞歸來實現。寫遞歸算法的時候,需要注意遞歸退出條件以及遞歸操作的表達。

自己的解法實現

def levelOrder4(self, root):
        from collections import deque
        if not root: return []

        queue, res = deque([(root)]), []
        while queue:
            level = []
            for _ in range(len(queue)):
                node = queue.popleft()
                level.append(node.val)
                if node.children:
                    queue.extend(node.children)
            res.append(level)
        return res

網上比較優秀的解法

解法一

方法一:利用隊列實現廣度優先搜索 我們要構造一個 sub-lists 列表,其中每個 sub-list 是樹中一行的值。行應該按從上到下的順序排列。

因爲我們從根節點開始遍歷樹,然後向下搜索最接近根節點的節點,這是廣度優先搜索。我們使用隊列來進行廣度優先搜索,隊列具有先進先出的特性。

在這裏使用棧是錯誤的選擇,棧應用於深度優先搜索。 用一個列表存放節點值,隊列存放節點。首先將根節點放到隊列中,當隊列不爲空時,則在隊列取出一個節點,並將其子節點添加到隊列中。

def levelOrder(self, root):
        from collections import deque
        if not root: return []
        queue = deque([(root)])
        res = []

        while queue:
            level = []
            for _ in range(len(queue)):
                node = queue.popleft()
                level.append(node.val)
                queue.extend(node.children)
            res.append(level)
        return res

解法二

廣度優先

def levelOrder2(self, root):
        if not root: return []
        res = []
        pre_layer = [root]

        while pre_layer:
            cur_layer = []
            res.append([])
            for node in pre_layer:
                res[-1].append(node.val)
                cur_layer.extend(node.children)
            pre_layer = cur_layer
        return res

解法三

方法三:遞歸 算法: 我們可以使用遞歸來解決這個問題,通常我們不能使用遞歸進行廣度優先搜索。這是因爲廣度優先搜索基於隊列,而遞歸運行時使用堆棧,適合深度優先搜索。但是在本題中,我們可以以不同的順序添加到最終列表中,只要我們知道節點在哪一層並確保在那一層的列表順序正確就可以了。

def levelOrder3(self, root):
        def traverse(node, level):
            if len(res) == level:
                res.append([])
            res[level].append(node.val)
            for child in node.children:
                traverse(child, level + 1)

        res = []
        if root:
            traverse(root, 0)
        return res

解法四

首先判斷root是否有內容,如果沒有則輸出[] 設置兩個列表queue,res,前者存放節點,後者存放值 開始循環,通過for循環將queue裏面的值分離出來一次性加入res中, queue隊列通過兩個for循環,前面一個取出queue的節點,後一個將取出的節點再取子節點,然後得到queue 最後循環結束輸出res

if not root: return []
        stack, res = [root], []

        while stack:
            res.append(node.val for node in stack)
            stack = [child for node in stack for child in node.children]
        return res

相關知識總結和思考

相關知識:

BFS:廣度/寬度優先。其實就是從上到下,先把每一層遍歷完之後再遍歷一下一層。

可以使用Queue的數據結構。我們將root節點初始化進隊列,通過消耗尾部,插入頭部的方式來完成BFS。

二叉搜索樹(BST)的特性:

  1. 若它的左子樹不爲空,則所有左子樹上的值均小於其根節點的值
  2. 若它的右子樹不爲空,則所有右子樹上的值均大於其根節點的值
  3. 它的左右子樹也分別爲二叉搜索樹

遞歸與迭代的區別

遞歸:重複調用函數自身實現循環稱爲遞歸; 迭代:利用變量的原值推出新值稱爲迭代,或者說迭代是函數內某段代碼實現循環;

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