1. 题目描述

给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。

说明:你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。

示例 1:

  1. 输入: root = [3,1,4,null,2], k = 1
  2. 3
  3. / \
  4. 1 4
  5. \
  6. 2
  7. 输出: 1

示例 2:

  1. 输入: root = [5,3,6,2,4,null,null,1], k = 3
  2. 5
  3. / \
  4. 3 6
  5. / \
  6. 2 4
  7. /
  8. 1
  9. 输出: 3

进阶:如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化 kthSmallest 函数?

2. 解题思路

我们知道,二叉搜索树的左节点小于其父节点,右节点小于其右节点。这样二叉搜索树的中序遍历就是一个从小到大的有序序列。我们可以根据这个特性进行解答。

递归:
对二叉搜索树进行中序遍历,遍历的原则就是先遍历左子树,然后遍历根节点,最后遍历左子树。在遍历过程中,将遍历的结果不断存入数组中,当遍历到第k个元素的时候,就终止遍历。

递归的时间复杂度为O(n),空间复杂度为O(n)。

迭代:
递归的方法也是利用的二叉搜索树的中序遍历:

  • 初始化一个栈暂存树的节点
  • 先遍历根节点,再遍历左子树,并保存在栈中
  • 遍历完左子树之后,将栈中的元素的出栈,这样顺序就反过来了,变成了先成遍历的根节点,再遍历的左子树
  • 在遍历的过程中,每遍历一次k就减一
  • 遍历完左子树之后再遍历右子树
  • 不断循环,直到k为0位置,返回当前的节点值。

迭代的时间复杂度为O(n),空间复杂度为O(n)。

3. 代码实现

递归:

  1. /**
  2. * Definition for a binary tree node.
  3. * function TreeNode(val, left, right) {
  4. * this.val = (val===undefined ? 0 : val)
  5. * this.left = (left===undefined ? null : left)
  6. * this.right = (right===undefined ? null : right)
  7. * }
  8. */
  9. /**
  10. * @param {TreeNode} root
  11. * @param {number} k
  12. * @return {number}
  13. */
  14. var kthSmallest = function(root, k) {
  15. const result = []
  16. function travel(node){
  17. if(result.length >= k) return
  18. if(node.left){
  19. travel(node.left)
  20. }
  21. result.push(node.val)
  22. if(node.right){
  23. travel(node.right)
  24. }
  25. }
  26. travel(root)
  27. return result[k - 1]
  28. };

迭代:

  1. /**
  2. * Definition for a binary tree node.
  3. * function TreeNode(val, left, right) {
  4. * this.val = (val===undefined ? 0 : val)
  5. * this.left = (left===undefined ? null : left)
  6. * this.right = (right===undefined ? null : right)
  7. * }
  8. */
  9. /**
  10. * @param {TreeNode} root
  11. * @param {number} k
  12. * @return {number}
  13. */
  14. let kthSmallest = function(root, k) {
  15. let stack = []
  16. let node = root
  17. while(node || stack.length) {
  18. // 遍历左子树
  19. while(node) {
  20. stack.push(node)
  21. node = node.left
  22. }
  23. node = stack.pop()
  24. if(--k === 0) {
  25. return node.val
  26. }
  27. node = node.right
  28. }
  29. return null
  30. }

4. 提交结果

递归:
230. 二叉搜索树中第K小的元素 - 图1
迭代:
230. 二叉搜索树中第K小的元素 - 图2