leetcode
 
解题思路
二叉搜索树(BST)的中序遍历结果是一个严格递增序列,利用这一特性:
- 中序遍历顺序:左子树 → 根节点 → 右子树
 
- 第 K 小元素:中序遍历的第 K 个节点即为所求
 
- 迭代优化:使用栈模拟中序遍历,找到第 K 个节点后立即终止遍历,避免全树遍历
 
区别于递归解法,迭代法空间复杂度更低(O(h)),且可提前终止
关键步骤
- 栈初始化:准备栈存储遍历路径
 
- 左子树入栈:从根节点开始,将所有左子节点入栈(保证最小节点在栈顶)
 
- 节点处理:
- 弹出栈顶节点(当前最小节点)
 
k-- 并检查 k==0(找到第 K 小元素) 
 
- 转向右子树:当前节点指向其右子节点,重复步骤2-3
 
代码实现
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}
func kthSmallest(root *TreeNode, k int) int {
    stack := []*TreeNode{} // 初始化栈
    for len(stack) > 0 || root != nil {
        // 1. 左子树入栈(深度优先)
        for root != nil {
            stack = append(stack, root)
            root = root.Left
        }
        // 2. 弹出当前最小节点
        n := len(stack)
        node := stack[n-1]
        stack = stack[:n-1]
        // 3. 检查是否第K小
        k--
        if k == 0 {
            return node.Val // 找到目标
        }
        // 4. 转向右子树
        root = node.Right
    }
    return -1 // k超出范围
}
 
 
 
示例测试
func main() {
    // 示例1:root = [3,1,4,null,2], k=1 → 输出1
    root1 := &TreeNode{Val: 3}
    root1.Left = &TreeNode{Val: 1}
    root1.Right = &TreeNode{Val: 4}
    root1.Left.Right = &TreeNode{Val: 2}
    fmt.Println(kthSmallest(root1, 1)) // 1
    // 示例2:root = [5,3,6,2,4,null,null,1], k=3 → 输出3
    root2 := &TreeNode{Val: 5}
    root2.Left = &TreeNode{Val: 3}
    root2.Right = &TreeNode{Val: 6}
    root2.Left.Left = &TreeNode{Val: 2}
    root2.Left.Right = &TreeNode{Val: 4}
    root2.Left.Left.Left = &TreeNode{Val: 1}
    fmt.Println(kthSmallest(root2, 3)) // 3
}
 
 
 
复杂度分析
| 指标 | 平衡树 | 最坏情况(链表) | 说明 | 
| 时间复杂度 | 
O(H + k) | 
O(n) | 
H为树高,k为查找序号 | 
| 空间复杂度 | 
O(H) | 
O(n) | 
栈深度最大为树高 | 
 
H与k的关系:
- 平衡树:H = log₂n,复杂度 ≈ O(log n + k)
 
- 最坏情况:树退化为链表,H = n,复杂度 O(n)
 
🔍 关键点总结
- BST特性利用:中序遍历有序性是核心依据
 
- 迭代优势:避免递归栈溢出,空间复杂度优化至O(h)
 
- 提前终止:找到第k个节点立即返回,减少无效遍历
 
- 边界处理:
- 空树直接返回-1
 
- k>节点数时返回-1(题目保证k有效可省略)
 
 
- 方向控制:左子树优先入栈保证升序访问