java数据结构与算法刷题-----LeetCode230. 二叉搜索树中第K小的元素
·
| java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846 |
|---|
1. 中序遍历
| 解题思路:时间复杂度O(H+k)其中H是树高,k是要找第几个结点。空间复杂度O(H) |
|---|
- 二叉搜索树,中序遍历序列就是升序排列。比如上面示例1的中序遍历结果为1,2,3,4,正好是升序序列
- 所以我们只需要进行中序遍历的过程中记录当前是第几个结点,如果是第k个,直接返回即可。
| 代码 |
|---|
- 递归法
class Solution {
int ans;//保存答案
int th=0;//保存当前遍历到第几个结点
public int kthSmallest(TreeNode root, int k) {
ans = root.val;//初始答案默认为根结点
dfs(root,k);
return ans;
}
public void dfs(TreeNode root , int k){
if(root == null) return;
if(th>=k)return;//如果已经找到第k个,就不用继续遍历了
dfs(root.left,k);//否则先遍历左子树
if(++th == k) ans = root.val;//然后判断是否到第k个,到了就记录当前结点值
dfs(root.right,k);//否则继续遍历右子树
}
}
- 迭代法
class Solution {
public int kthSmallest(TreeNode root, int k) {
Deque<TreeNode> stack = new ArrayDeque<TreeNode>();//迭代法深度优先
//中序遍历迭代法,
while (root != null || !stack.isEmpty()) {
while (root != null) {//先遍历左子树
stack.push(root);
root = root.left;
}
root = stack.pop();//遍历中间结点
if (--k == 0) break;//同时进行k--,当k为0时,表示找到了
root = root.right;//然后遍历右子树
}
return root.val;
}
}
2. 预处理
如果需要频繁进行查找第k个元素的操作,就不能每次都进行中序遍历,太费时间了,平均时间复杂度会很高
所以我们记录每个结点的左子结点个数,和右子结点个数
- 当前node.left的结点个数<k-1,则第k小元素在node.right. 此时去右边只需找第k - left - 1个元素即可
- node.left结点个数 = k-1,则第k小元素为node,返回node即可
- node.left结点个数 > k-1,则第k小元素在node.left,令node = node.left继续搜索即可
| 代码:此算法做题肯定慢,但是实战中,仅仅是第一次预处理时会慢,之后再查的时候就会很快了 |
|---|
class Solution {
public int kthSmallest(TreeNode root, int k) {
MyBst bst = new MyBst(root);
return bst.kthSmallest(k);
}
}
class MyBst {
TreeNode root;
Map<TreeNode, Integer> nodeNum;
public MyBst(TreeNode root) {
this.root = root;
this.nodeNum = new HashMap<TreeNode, Integer>();
countNodeNum(root);
}
// 返回二叉搜索树中第k小的元素
public int kthSmallest(int k) {
TreeNode node = root;
while (node != null) {
int left = getNodeNum(node.left);
if (left < k - 1) {
node = node.right;
k -= left + 1;
} else if (left == k - 1) {
break;
} else {
node = node.left;
}
}
return node.val;
}
// 统计以node为根结点的子树的结点数
private int countNodeNum(TreeNode node) {
if (node == null) {
return 0;
}
nodeNum.put(node, 1 + countNodeNum(node.left) + countNodeNum(node.right));
return nodeNum.get(node);
}
// 获取以node为根结点的子树的结点数
private int getNodeNum(TreeNode node) {
return nodeNum.getOrDefault(node, 0);
}
}
更多推荐




所有评论(0)