LeetCode Notes_#173_二叉搜尋樹迭代器
阿新 • • 發佈:2020-08-09
LeetCode Notes_#173_二叉搜尋樹迭代器
LeetCodeContents
題目
實現一個二叉搜尋樹迭代器。你將使用二叉搜尋樹的根節點初始化迭代器。
呼叫 next() 將返回二叉搜尋樹中的下一個最小的數。
示例:
BSTIterator iterator = new BSTIterator(root); iterator.next(); // 返回 3 iterator.next(); // 返回 7 iterator.hasNext(); // 返回 true iterator.next(); // 返回 9 iterator.hasNext(); // 返回 true iterator.next(); // 返回 15 iterator.hasNext(); // 返回 true iterator.next(); // 返回 20 iterator.hasNext(); // 返回 false
提示:
- next()和hasNext()操作的時間複雜度是O(1),並使用O(h) 記憶體,其中h是樹的高度。
- 你可以假設next()呼叫總是有效的,也就是說,當呼叫 next()時,BST 中至少存在一個下一個最小的數。
思路分析
迭代數字的順序是從小到大,也就是BST的中序遍歷的順序。
方法1:在構造器中得到中序遍歷序列
寫一箇中序遍歷的輔助方法,在構造器中呼叫它,把中序遍歷序列儲存下來。next()
方法只需要按順序訪問中序遍歷序列的每個數字即可。
但是空間複雜度不符合要求。
方法2:拆分非遞迴中序遍歷模板
其實就是非遞迴中序遍歷二叉樹的變體,只需要把程式碼拆分到三個方法當中即可。
以下是非遞迴中序遍歷的模板。
class Solution {
public List<Integer> inOrderTraversal(TreeNode root) {
if (root == null) {
return new LinkedList<>();
}
List<Integer> res = new LinkedList<>();
Deque<TreeNode> stack = new LinkedList<>();
TreeNode node = root;
//以上屬於初始化部分,寫在構造器中
//以下一行是迴圈終止條件,寫在hasNext()中
while(node != null || !stack.isEmpty()) {
//以下是迴圈體,寫在next()中
while (node != null) {
stack.addLast(node);
node = node.left;
}
node = stack.removeLast();
res.add(node.val);
node = node.right;
}
return res;
}
}
模板大法好。
解答
解答1:在構造器中得到中序遍歷序列
不符合空間複雜度要求,僅供參考。
class BSTIterator {
List<Integer> inorder;
int index = 0;
public BSTIterator(TreeNode root) {
inorder = new ArrayList<>();
inorderRecur(root);
}
//得到中序遍歷序列
private void inorderRecur(TreeNode root){
if(root == null) return;
inorderRecur(root.left);
inorder.add(root.val);
inorderRecur(root.right);
}
//返回當前節點的值;然後index增加1,指向下一節點
/** @return the next smallest number */
public int next() {
return inorder.get(index++);
}
//判斷當前的index索引是否越界
/** @return whether we have a next smallest number */
public boolean hasNext() {
return index <= inorder.size() - 1;
}
}
複雜度分析
構造器
時間複雜度:O(n)
空間複雜度:O(n)
next()
,hasNext()
方法
時間複雜度:O(1)
空間複雜度:O(n)
,因為藉助了額外的inorder
陣列。
所以是不符合題目要求的,因為題目要求空間複雜度是O(h)
。
解答2:拆分非遞迴中序遍歷模板
//對非遞迴中序遍歷模板進行簡單的拆分即可
class BSTIterator {
TreeNode node;
LinkedList<TreeNode> stack;
//初始化部分寫到構造器當中
public BSTIterator(TreeNode root) {
node = root;
stack = new LinkedList<>();
}
//next()方法其實就是中序遍歷的迴圈體
/** @return the next smallest number */
public int next() {
while(node != null){
stack.addLast(node);
node = node.left;
}
node = stack.removeLast();
int val = node.val;
node = node.right;
return val;
}
//hasNext()方法就是中序遍歷的迴圈條件
/** @return whether we have a next smallest number */
public boolean hasNext() {
return node != null || !stack.isEmpty();
}
}
複雜度分析
時間複雜度
next()
:所有的n個節點都會入棧,但是並不是每次呼叫next
就入棧一個,有時候呼叫一次next
入棧多個節點,有時候則沒有節點入棧。整體來看,next()
被呼叫n次,總共入棧n個節點,平均下來是O(1)
。hasNext()
:這個就不用說了,每次呼叫的複雜度都是O(1)
空間複雜度:O(h)
- 雖然所有的n個節點都入棧,但是棧中元素最多隻有h(即樹的深度)。
- 棧中元素最多的時候就是剛開始將最左邊的一溜全部入棧的時候,剛好是h。