Given a binary search tree, write a function kthSmallest
to find the kth smallest element in it.
Note:
You may assume k is always valid, 1 ≤ k ≤ BST's total elements.
Example 1:
Input: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
Output: 1
Example 2:
Input: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
Output: 3
Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?
首先,
二叉树中序遍历的第k个数就是第k大。二叉树中序遍历是从小到大有序的。
中序,先序,后续都是dfs遍历。
所以先来看看二叉树中序遍历的代码:
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new LinkedList<Integer>();
Stack<TreeNode> stack = new Stack<TreeNode>();
while(root!=null || !stack.isEmpty()){
while(root != null){
stack.push(root);
root = root.left;
}
root = stack.pop();
res.add(root.val);
root = root.right;
}
return res;
}
也可以这样:
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new LinkedList<Integer>();
Stack<TreeNode> stack = new Stack<TreeNode>();
while(root!=null || !stack.isEmpty()){
if(root != null){
stack.push(root);
root = root.left;
}
else{
root = stack.pop();
res.add(root.val);
root = root.right;
}
}
return res;
}
知道了二叉树中序遍历的循环写法后,就写出了二叉树第k大问题的解
//二叉树中序遍历的第k个数就是第k大。二叉树中序遍历是从小到大有序的
public int kthSmallest(TreeNode root, int k) {
Stack<TreeNode> stack = new Stack<TreeNode>();
while(root!=null || !stack.isEmpty()){
while(root != null){
stack.push(root);
root = root.left;
}
root = stack.pop();
if(--k==0) break;//root是第k大的节点
root = root.right;
}
return root.val;
}
当然,也可以循递归来写二叉树中序遍历,这样子得到第二种解法:
int count = 0;
int result = 0;//随便初始,没关系
public int kthSmallest(TreeNode root, int k) {
inordertraverse(root, k);
return result;
}
public void inordertraverse(TreeNode root, int k) {
if(root == null) return;
inordertraverse(root.left, k);
count++;
if(count == k){
result = root.val;
return;
}
inordertraverse(root.right, k);
}
后记:
一般我们想要循环写法而不是递归写法,因为递归写法可能造成内存溢出。
一般情况下,树的高度为O(lgn),递归写法也没问题。
但是最坏情况下,树的高度可能是O(n)的,那么n层递归很可能造成内存溢出!!!
所以要使用循环写法