一个容易想到的想法是基于二叉树,只要对二叉树进行中序遍历,序列中第k个元素就是想要找的第k小的元素。
在这里,我还会介绍另一解法。基于binar search的,这个方法的效率更高。
解法1:中序遍历。
中序遍历可以通过递归的方式,也可以通过迭代的方式。
基本思想就是当我已经输出到第k个元素了,我就可以直接返回这个元素了,后面的遍历不需要再进行了。
代码:就是在之前的中序遍历上进行修改,不需要存储结果的list。
而是设置一个k变量,每次输出一个树就-1,当k = 0时候,返回遍历到的元素。
代码:
public int kthSmallestByInOrderIterative(TreeNode root, int k) {
Stack<TreeNode> store = new Stack<>();
if (root == null) {
return -1;
}
store.push(root);
while (root.left != null) {
store.push(root.left);
root = root.left;
}
while (!store.empty()) {
TreeNode cur = store.pop();
k--;
if (k == 0) {
return cur.val;
}
if (cur.right != null) {
root = cur.right;// let cur.right be the current node
store.push(root);
while (root.left != null) {
store.push(root.left);
root = root.left;
}
}
}
return -1;
}
解法2:binary seach
二分的思想是我每次看看当前节点的左子树中有多少个元素,记为count。
如果我的k <= count,那么显然第k小的树在左子树中,在左子树中继续进行二分搜索。
如果我的k == count + 1, 那么当前节点恰好是这个第k小的节点,直接返回节点点。
如果我的k > count + 1, 那么第k小的节点在右子树,在右子树中继续进行二分搜索。
代码:
public int kthSmallestByBinarySearch(TreeNode root, int k) {
int count = countNum(root.left);
if (k == count + 1) {
return root.val;
} else if (k <= count) {
return kthSmallestByBinarySearch(root.left, k);
} else {
return kthSmallestByBinarySearch(root.right, k - 1 - count);// count is the left tree num, 1 is the root
}
}
private int countNum(TreeNode node) {
if (node == null) {
return 0;
}
return 1 + countNum(node.left) + countNum(node.right);
}
参考资料:
https://leetcode.com/discuss/43771/implemented-java-binary-search-order-iterative-recursive