LeetCode #106 Construct Binary Tree from Postorder and Inorder Traversal - 刷題之旅
1 題目描述
提供給你 postorder 與 inorder 的數列,請你建立一個二元樹。首先 讓我們先了解 postorder 與 inorder 的定義。
Inorder Traversal -> LEFT -> ROOT -> RIGHT
Postorder Traversal -> LEFT -> RIGHT -> ROOT
2 解法
這題跟 105 題很像,只是順序不同,這題是 postorder 與 inorder,105 題是 preorder 與 inorder。這題的解法也是利用遞迴的方式來建立二元樹。
你會發現,postorder 最後一筆會是 Root,前面會先遍歷left sub-tree整顆跑完,才會再遍歷right sub-tree。而 inorder 是先遍歷left sub-tree,再遍歷root,最後是right sub-tree。你會發現 preorder 跟 inorder 的優缺點如下:
- postorder:
- 好處:因為最後一個值是root,所以可以直接取得root的值
- 缺點:無法知道左右子樹的範圍
- inorder:
- 好處:可以知道左右子樹的範圍
- 缺點:無法知道root的值
因此我們要利用彼此雙方的好處,互補彼此的缺點。這時候我們就可以利用遞迴的方式來建立二元樹。
2.1 取subtree的範圍
Step1: 在postorder找到root + 在 inorder找到左右子樹長度
- 那就是如果我們先取得postorder的最後一個值,就可以知道root的值是什麼
- 然後再根據這個值去inorder中找到root的位置,這樣就可以知道左右子樹的範圍。
- 左子樹起點=0 ~ 左子樹 root_index (不包含) 簡單來說就是
inorder[0:root_index]
- 右子樹起點=root_index+1 ~ 右子樹結束點=len(inorder) (包含) 簡單來說就是
inorder[root_index+1:]
- 左子樹起點=0 ~ 左子樹 root_index (不包含) 簡單來說就是
大概是這種感覺:
1 | def buildTree(self, inorder: List[int], postorder: List[int], ) -> Optional[TreeNode]: |
Step2: 根據左右子樹的長度,在postorder切割左右子樹
因為我們用inorder知道了左右子樹的,我們就可以在 postorder 裡面開始切割左右子樹
- 使用
i_left
的長度,在[1:]
切割左子樹 - [0+1:] 這個區間是由 左子樹 + 右子樹 所組成
- 左子樹起點=0 ~ 左子樹結束點=1+left_len (不包含) 簡單來說就是
postorder[0:left_len+1]
- 右子樹起點=1+left_len ~ 右子樹結束點=-1 (包含) 簡單來說就是
postorder[left_len+1:-1]
- 左子樹起點=0 ~ 左子樹結束點=1+left_len (不包含) 簡單來說就是
- 從 postorder 得到的左右子樹,取最後一個值,又可以得到 root
- 把postorder從[:-1] 切成兩半左右子樹後,我們又可以開始遞迴,找到這兩個子樹的 root
大概是這種感覺:
1 | def buildTree(self, inorder: List[int], postorder: List[int], ) -> Optional[TreeNode]: |
Step3: 當左右子樹為空時,回傳None
1 | def buildTree(self, inorder: List[int], postorder: List[int], ) -> Optional[TreeNode]: |
精簡
稍微整理以下就可以變成這樣
1 | def buildTree(self, inorder: List[int], postorder: List[int], ) -> Optional[TreeNode]: |
總結一下順序:
- inorder切出左右子樹: 在 inorder 用 root 切出左右子樹的範圍
- inorder找出左右子樹長度:拿 inorder 左右子樹的長度,在 postorder 切出左右子樹的範圍
- postorder 切出左右子樹,以找出root: postorder 的左右子樹一出來,就可以知道左右子樹的 root 是什麼(因為 postorder 的第一個值是root)
- 大小問題關係式: 然後把 root.left 與 root.right 填入
2.2 queue 的解法
跟 105 題一樣,可以使用queue去解這題,這樣就不用一直切割list,可以直接用index去取值,這樣會比較快。
1 | def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: |
3 總結
因為已經寫過了,所以大概30分鐘內就可以解決
本部落格所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明來自 Shannon's Blog 🐟 技術 | 生活 | 旅行! 如果你覺得我的文章有幫助,希望你可以到我的 github 給我一個 star ⭐️ Shannon Blog Repo
評論