【力扣】從中序與後序遍歷序列構造二叉樹
來源:力扣(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 defbuildTree(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,滿足所有情況。
當然效果慘不忍睹: