在问 · 算法题解

173. 二叉搜索树迭代器

中等设计受控递归(栈模拟中序遍历)力扣原题 ↗

题目描述

实现类 BSTIterator,它按中序遍历的顺序逐个取出一棵二叉搜索树中的值。可以把它想成一个在中序序列上移动的指针。

- BSTIterator(TreeNode root):用根节点 root 创建迭代器。指针最初停在一个比树中所有值都小、且不在树中的位置,因此第一次调用 next() 会得到最小值。 - boolean hasNext():指针右边还有值时返回 true,否则返回 false。 - int next():把指针右移一位,返回所指的值。

调用 next() 时一定还有下一个值可取。树以层序数组给出,例如 [7,3,15,null,null,9,20],null 表示空位。

示例 1
输入:操作 = ["BSTIterator","next","next","hasNext","next","hasNext","next","hasNext","next","hasNext"]
参数 = [[[7,3,15,null,null,9,20]],[],[],[],[],[],[],[],[],[]]
输出:[null,3,7,true,9,true,15,true,20,false]

解释:中序序列是 3、7、9、15、20,next() 依次取出这些值;取完 20 后 hasNext() 返回 false。

数据范围

  • 树中节点数在 [1, 10^5] 范围内。
  • 0 <= Node.val <= 10^6
  • hasNext 和 next 合计最多调用 10^5 次。

进阶:能否让 next() 和 hasNext() 的均摊时间为 O(1),并且只用 O(h) 内存?h 是树高。

解题思路:受控递归(栈模拟中序遍历)

把递归中序遍历拆开,用一个显式栈保存“还没访问的祖先”。构造时把根的整条左链压栈,此时栈顶就是最小值。next 弹出栈顶 node 作为答案;比 node 大的下一个数在它的右子树最左端,所以对 node.right 再压一次左链。hasNext 只需判断栈是否为空。

为什么正确

栈中节点从底到顶严格递减,栈顶是下一个要返回的节点;所有未访问的节点要么在栈里,要么在栈中某个节点的右子树里。

复杂度分析

next 均摊 O(1)(每个节点只入栈、出栈各一次),hasNext O(1);空间 O(h)。

易错点

弹出节点后只压入 node.right 本身是错的,必须把右子树的整条左链都压入,否则下一个返回的不是最小值。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class BSTIterator:
    def __init__(self, root: Optional[TreeNode]):
        self.stack = []
        self.push_left(root)

    def push_left(self, node):
        while node:
            self.stack.append(node)
            node = node.left

    def next(self) -> int:
        node = self.stack.pop()
        self.push_left(node.right)
        return node.val

    def hasNext(self) -> bool:
        return len(self.stack) > 0

载入编辑器,自己跑一遍 →

其他解法

展开数组一次性完成全部遍历,占 O(n) 空间;栈解法按需推进遍历,只保存一条左链,空间 O(h)。

解法 2:中序遍历展开成数组 时间 初始化 O(n),操作 O(1),空间 O(n)

构造时对整棵树做一次递归中序遍历,把结点值按升序存进数组,并记录一个下标 idx。next() 返回数组[idx] 并让 idx 加一,hasNext() 判断 idx 是否小于数组长度。

实现最简单,每次操作严格 O(1)。要保存整棵树的 n 个值,不满足进阶要求的 O(h) 空间。

class BSTIterator:
    def __init__(self, root):
        self.vals = []
        self.idx = 0
        self.inorder(root)

    def inorder(self, node):
        if node is None:
            return
        self.inorder(node.left)
        self.vals.append(node.val)
        self.inorder(node.right)

    def next(self) -> int:
        self.idx += 1
        return self.vals[self.idx - 1]

    def hasNext(self) -> bool:
        return self.idx < len(self.vals)

设计 专题的其他题目

查看 设计 全部题目 →