1. 程式人生 > 實用技巧 >【力扣】從中序與後序遍歷序列構造二叉樹

【力扣】從中序與後序遍歷序列構造二叉樹

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal

根據一棵樹的中序遍歷與後序遍歷構造二叉樹。

注意:
你可以假設樹中沒有重複的元素。

例如,給出

中序遍歷 inorder =[9,3,15,20,7]
後序遍歷 postorder = [9,15,7,20,3]
返回如下的二叉樹:

3
/ \
9 20
/ \
15 7

我寫的第一版程式碼如下,大部分測試用例均可以通過:

 1 class Solution:
 2     def
buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode: 3 if len(inorder) > 0 and len(postorder) >0 : 4 root = postorder[-1] 5 root_idx = inorder.index(root) 6 result = TreeNode() 7 result.val = inorder[root_idx] 8 result.left = Solution.buildTree(self,inorder[:root_idx],postorder[:root_idx])
9 result.right = Solution.buildTree(self,inorder[root_idx+1:],postorder[len(inorder[:root_idx]):(len(postorder)-len(inorder[:root_idx]))]) 10 return result

思路如下:

前序遍歷:訪問順序:根節點->左節點->右節點

中序遍歷:訪問順序:左節點->根節點->右節點

後序遍歷:訪問順序:左節點->右節點->根節點

我依稀記得考研複習的時候,給出前中兩遍歷,可以還原出二叉樹;給出中後兩遍歷。也可以還原出二叉樹;給出前後兩遍歷是不能還原二叉樹的。

題目給出了中後兩遍歷序列,我們首先分析兩個list :inorder =[9,3,15,20,7],postorder = [9,15,7,20,3]

因為後序遍歷總是最後在訪問根節點,所以我們可以知道3為本棵二叉樹的根節點,我們又知道中序遍歷先訪問根節點的左子樹(節點)再訪問跟節點,於是我們可以在inorder中定位到根節點3,以及這顆二叉樹的左子樹元素(9)與右子樹元素(15,20,7)。

   3
  / \
9  (15,20,7)

利用遞迴的思想,將左子樹與右子樹看作一個新的二叉樹不斷重複上述過程,就能得到題目要求的結果。

問題的關鍵在於每次遞迴呼叫,左右子樹的inorder,postorder如何準確給出。

我的思路程式設計是先拿到後序遍歷序列的最後一個元素(根節點),在前序遍歷序列中找到根節點對應的下標,根節點下標以左的list作為左子樹的inorder,根節點下標以右的list作為右子樹的inorder;左子樹的postorder比較容易獲得,因為中後序遍歷都是先訪問左子樹,因此postorder[:root_idx]可以將左子樹的postorder獲取,而右子樹的postorder需要作減法來獲得對應的list的取值範圍,我選擇使用postorder/inorder的總長度減去左子樹postorder的長度,獲得取值範圍,再選擇從左子樹最後一個元素的下標後的第一個元素作為起始下標,所以這句程式碼看起來很長:

postorder[len(inorder[:root_idx]):(len(postorder)-len(inorder[:root_idx]))]

但是當len(inorder)與len(postorder)=2時,會有一個小bug執行測試用例inorder = [1,2],postorder = [2,1]出錯,手動執行一遍:

root = postorder[-1] = 1

root_idx = inorder.index(root) = 0

建立一棵樹 result = TreeNode( )

將根節點的值儲存入 result.val = 1

result.left為空

result.right = Solution.buildTree(self,inorder[1:],postorder[0:2]) inorder[1:] = [2] ,postorder = [2,1]

進入buildTree( ),中序遍歷與後序遍歷長度不同,肯定要報錯

是因為我使用減法獲取右子樹後序遍歷序列出現問題當postorder初始值較小時該方法不行,所以

 1 class Solution:
 2     def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
 3         if len(inorder) > 0 and len(postorder) > 0 :
 4             root = postorder[-1]
 5             root_idx = inorder.index(root)
 6             result = TreeNode()
 7             result.val = inorder[root_idx]
 8             result.left = Solution.buildTree(self,inorder[:root_idx],postorder[:root_idx])
 9             result.right = Solution.buildTree(self,inorder[root_idx+1:],postorder[len(inorder[:root_idx]):-1])
10             return result

轉變思路從列表結尾開始思考,發現後序遍歷列表從len(inorder[:root_idx])到最後一個元素(根節點)之前均為右子樹的後序遍歷List,所以直接一個-1,滿足所有情況。

當然效果慘不忍睹: