LeetCode #173 Binary Search Tree Iterator - 刷題之旅
1 題目描述
簡單來說,這題是要實作一個Binary Search Tree的iterator,這個iterator可以讓你用next()
的方式來取得下一個最小的值。然後使用 hasNext()
來判斷是否還有下一個最小值。
注意:題目有要求,空間複雜度必須是O(h)
,h
是樹的高度。
2 解法
當你看到 next()
目的是在取得『最小值』時。因為BST的特性是,任意節點的左子樹不空,那左子樹上所有節點的值均小於他的根節點的值。因此我們可以使用 inorder traversal
的方式來解這題,因為 inorder traversal
是一種由小到大(左-中-右)的方式遍歷BST。詳細關於inorder得實作可以參考這篇LeetCode 課前預習 - 掌握 BFS 與 DFS 指南。
2.1 解法1: Inorder Traversal
這邊我們可以使用stack
來幫助我們做inorder traversal
,然後每次呼叫next()
的時候,我們就可以取得最小的值,在 hasNext()
的時候,我們只要判斷stack
是否為空就可以了。
1 | class BSTIterator: |
但是上面的解法,空間複雜度是O(n)
,不符合題目要求,上面的程式問題在於 _inorder
的時候,把所有節點都放進stack
裡面,這樣空間複雜度就是O(n)
。
2.2 解法2: Iterator with Stack
在解法1中,我們把所有的節點都保存起來了,但其實沒必要一次性保存所有節點,我們應該要控制stack塞入節點的時機,這樣就可以達到O(h)
的空間複雜度。具體該怎麼做,我們來釐清一下:
第一種情境
當我們初始化BSTIterator
的時候,在呼叫next()
時,我們希望回傳最小值,而題目要求空間複雜度是O(h)
,所以我們就遍歷到底,直到取到最小值,這個遍歷的過程中,我們可以把遍歷的節點都放進stack裡面,這樣就可以達到O(h)
的空間複雜度。所以第一種狀況的程式碼大概是這樣:
1 | while cur: |
第二種情境
接下來我們要考慮的是,當我們呼叫next()
的時候,具體要考慮哪些事情,這裡分成兩個部分:
- 當我們呼叫
next()
的時候,我們要回傳最小值,也就是stack的最上面的節點。 - 當我們取出最小值後,指標往上移動,因為下次取
next()
時也是從stack中pop出來,但是我們的stack還沒有放任何右子樹的節點,因此每次pop出來後,我們就要檢查,right是否有值,如果有也要將右子樹遍歷到最小值的所有節點壓到stack中,這樣下次呼叫next()
的時候,就可以取得下一個最小值。
1 | res = stack.pop() |
那基本上我們就可以實作這個iterator了,我們把情境1的程式碼包裝成_leftmost_inorder()
,最後程式碼如下:
1 | class BSTIterator: |
3 結論
其實這題不難,只是要先能夠想到 inorder 然後根據 inorder 的演算法做變體。這題的重點在於如何控制stack塞入的過程,這樣就可以達到O(h)
的空間複雜度。