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;
dfs(root.left,k);
if(++th == k) ans = root.val;
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;
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);
}
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;
}
private int countNodeNum(TreeNode node) {
if (node == null) {
return 0;
}
nodeNum.put(node, 1 + countNodeNum(node.left) + countNodeNum(node.right));
return nodeNum.get(node);
}
private int getNodeNum(TreeNode node) {
return nodeNum.getOrDefault(node, 0);
}
}