[ LeetCode 107 ] N叉樹層序遍歷
每天分享一個LeetCode題目
每天 5 分鐘,一起進步
LeetCode N叉樹層序遍歷,地址: https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/
樹結點類
class Node(object):
def __init__(self, val=None, children=[]):
self.val = val
self.children = children
N叉樹的特殊性,就是一個結點可能會包含N個結點,所以,每個結點的孩子結點設定為陣列
層序遍歷
層序遍歷對於很多時候,都是面試經常問到的內容。
尤其是這裡有個小點,可能會讓大家咯噔一下,就是對於結點的列印方式。
比如,樹的結構是:
A
/ | \
B C D
/|\ / \
E F G H I
結果列印的方式會有兩種:
一種是普通遍歷,直接列印
另外一種是每個層級中的元素單獨列印,也是LeetCode429 要求的格式
# 第一種
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
# 第二種
[['A'], ['B', 'C', 'D'], ['E', 'F', 'G', 'H', 'I']]
第一種很簡單,第二種可能需要一些小小的中間結果記錄,咱們分開說說...
第一種層序遍歷
1.初始化結果集res,初始化佇列queue,將根結點放置到queue中;
2.只要queue不為空,迴圈遍歷,每次遍歷將隊首元素防止到 res 中,之後將隊首元素的孩子結點依次入隊;
3.迴圈執行第 2 點。
看看程式碼:
def levelOrder_basic(self, root): # 初始化結果集res res = [] # 初始化佇列queue,將根結點放置到queue中 queue = collections.deque() queue.appendleft(root) while(queue): # 每次遍歷將隊首元素防止到 res 中 pop_node = queue.pop() res.append(pop_node.val) # 將隊首元素的孩子結點依次入隊 for node in pop_node.children: queue.appendleft(node) return res
其實比較簡單,就是將遍歷到的結點放置到結果集中,同時將結點的孩子結點入隊,之後迴圈進行就好!
第二種層序遍歷
這種遍歷,有一點難處就是要將每一層級的元素單獨放置到陣列中,然後將每一層級的陣列放置到最後的陣列中
這樣:
[['A'], ['B', 'C', 'D'], ['E', 'F', 'G', 'H', 'I']]
類似於 第一種 層序遍歷,需要改變的就是要將每一層級的元素單獨遍歷
1.初始化結果集res,初始化佇列queue,將根結點放置到queue中;
(注意:此處的queue放置的是每一層的結點元素,不理解沒關係,往下看)
2.只要queue不為空,迴圈遍歷,同時初始化兩個臨時陣列
第一個:tmp_res = [],臨時存放每一層遍歷訪問到的結點,最終會合併到結果res中
第二個:tmp_queue = [],臨時存放下一層的結點元素,用於下一個迴圈的遍歷
每次遍歷將隊首元素防止到 tmp_res 中,之後將隊首元素的孩子結點依次入隊 tmp_queue
最後,將 tmp_queue 賦值給 queue,tmp_res併入到最終結果集 res
3.迴圈執行第 2 點,直到 queue 為空
4.返回最終結果集 res
看程式碼
def levelOrder(self, root):
# 最終結果
res = []
if not root:
return res
# 初始化佇列,並且將根結點置入佇列中
# 存放每一個層級的結點
queue = collections.deque()
queue.appendleft(root)
while(queue):
# 臨時存放結點的佇列,最終合併到最後的 res 中
tmp_res = []
# 臨時存放下一層結點的佇列
tmp_queue = []
for node in queue:
tmp_res.append(node.val)
# 將孩子結點放置到 tmp_queue 中
for child_node in node.children:
tmp_queue.append(child_node)
# 將 tmp_queue 賦值給 queue,tmp_res併入到最終結果集 res
queue = tmp_queue
res.append(tmp_res)
看著比較複雜,其實關鍵有一點,之前迴圈遍歷 queue 就好,現在是把每一層結點動態的賦值給 queue,也就是說每一次迴圈遍歷,queue 中的值是當前層的結點集。
動手畫一畫就會看起來很簡單了哈!
全部程式碼
# -*- coding:utf-8 -*-
# !/usr/bin/env python
import collections
# 樹結點類
class Node(object):
def __init__(self, val=None, children=[]):
self.val = val
self.children = children
class Solution(object):
def levelOrder_basic(self, root):
"""
基礎的層序遍歷,就是把每一層的結點值一次性打印出來
類似於 ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] 這樣
:param root:
:return:
"""
res = []
queue = collections.deque()
queue.appendleft(root)
while(queue):
pop_node = queue.pop()
res.append(pop_node.val)
for node in pop_node.children:
queue.appendleft(node)
return res
def levelOrder(self, root):
"""
層序遍歷(LeetCode中規定的格式),即把每一層的結點放進各自的陣列中
類似於[['A'], ['B', 'C', 'D'], ['E', 'F', 'G', 'H', 'I']] 這樣
:param root:
:return:
"""
# 最終結果
res = []
if not root:
return res
# 初始化佇列,並且將根結點置入佇列中
# 存放每一個層級的結點
queue = collections.deque()
queue.appendleft(root)
while(queue):
# 臨時存放結點的佇列,最終合併到最後的 res 中
tmp_res = []
# 臨時存放下一層結點的佇列
tmp_queue = []
for node in queue:
tmp_res.append(node.val)
# 將孩子結點放置到 tmp_queue 中
for child_node in node.children:
tmp_queue.append(child_node)
queue = tmp_queue
res.append(tmp_res)
return res
if __name__ == "__main__":
# 新建節點
root = Node('A')
node_B = Node('B')
node_C = Node('C')
node_D = Node('D')
node_E = Node('E')
node_F = Node('F')
node_G = Node('G')
node_H = Node('H')
node_I = Node('I')
# 構建三叉樹
# A
# / | \
# B C D
# /|\ / \
# E F G H I
root.children = [node_B, node_C, node_D]
node_B.children = [node_E, node_F, node_G]
node_D.children = [node_H, node_I]
s = Solution()
print(s.levelOrder_basic(root))
print(s.levelOrder(root))
可以直接執行哈!