给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。
https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/
**进阶:**如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k
小的值,你将如何优化算法?
示例1:
3 / \ 1 4 \ 2
输入:root = [3,1,4,null,2], k = 1
输出:1
示例2:
5 / \ 3 6 / \ 2 4 / 1
输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3
提示:
树中的节点数为 n 。
1 <= k <= n <= 104
0 <= Node.val <= 104
Java解法
思路:
二叉搜索树的特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
寻找第k小,
可以用快慢指针的方式,先对左子树进行遍历,如果左子树所有结点数量小于k,那对右子树进行遍历,同时k-左子树节点数量+根节点1,重复的操作因为无法估量到底的问题,改用栈来存储左子树,弹出时对右子树遍历记数效率不高,但思路有效
package sj.shimmer.algorithm.m4_2021;
import java.util.Stack;
import sj.shimmer.algorithm.TreeNode;
/**
* Created by SJ on 2021/4/21.
*/
class D84 {
public static void main(String[] args) {
TreeNode root = new TreeNode(
3,
new TreeNode(1,null,new TreeNode(2)
),
new TreeNode(4)
);
System.out.println(kthSmallest(root,1));
System.out.println(kthSmallest(root,2));
System.out.println(kthSmallest(root,3));
System.out.println(kthSmallest(root,4));
TreeNode node = TreeNode.getInstance(new Integer[]{5, 3, 6, 2, 4, null, null, 1});
System.out.println(kthSmallest(node,1));
System.out.println(kthSmallest(node,2));
System.out.println(kthSmallest(node,3));
System.out.println(kthSmallest(node,4));
System.out.println(kthSmallest(node,5));
System.out.println(kthSmallest(node,6));
}
static int count = 0;
public static int kthSmallest(TreeNode root, int k) {
count = k;
return kthSmallest(root);
}
public static int kthSmallest(TreeNode root) {
//使用栈储找到最小结点的过程
Stack<TreeNode> stack = new Stack<>();
TreeNode min = root;
while (min != null) {
stack.add(min);
min =min.left;
}
//开始弹出
while (!stack.isEmpty()&&count>0) {
TreeNode pop = stack.pop();
//为当前的最小值
count--;
if (count==0) {
return pop.val;
}else {
int result = kthSmallest(pop.right);
if (result!=-1) {
return result;
}
}
}
return -1;
}
}
官方解
-
遍历树
深度优先搜索(DFS)
广度优先搜索(BFS)通过中序遍历获取,利用递归形式
- 时间复杂度:O(N)
- 空间复杂度:O(N)
-
迭代
类似我的思路,但我比较二,本身用了栈,还死脑筋转去递归了,导致效率上差很多
public int kthSmallest(TreeNode root, int k) { LinkedList<TreeNode> stack = new LinkedList<TreeNode>(); while (true) { while (root != null) { stack.add(root); root = root.left; } root = stack.removeLast(); if (--k == 0) return root.val; root = root.right; } }