不要被题目迷惑,肯定是要O(N)的时间,在不改变数据结构的情况下。
就是in-order traverse,因为是BST,所以遍历顺序是从小到大,遍历的第K个元素就是第K小的。
可以Iteratively,也开始recursively.
public class Solution
{
/* recursion version
int count = 0;
int res = 0;
public int kthSmallest(TreeNode root, int k)
{
helper(root,k);
return res;
}
public void helper(TreeNode root, int k)
{
if(root == null || count == k) return;
helper(root.left,k);
count++;
if(count == k)
{
res = root.val;
return;
}
helper(root.right,k);
}
*/
public int kthSmallest(TreeNode root, int k)
{
int res = 0;
int count = 0;
Stack<TreeNode> stk = new Stack<TreeNode>();
TreeNode temp = root;
while(temp != null || !stk.isEmpty())
{
while(temp!=null)
{
stk.push(temp);
temp = temp.left;
}
temp = stk.pop();
count++;
if(count == k)
{
res = temp.val;
break;
}
if(count>=k)break;
temp = temp.right;
}
return res;
}
}
至于follow up,无非是如何提供信息,让每次左还是右能做出选择。Node的结构里直接加1个数表示第几小的,这样遍历就知道往左还是往右了。
二刷
又一次被follow up给迷惑了,以为有O(height)的做法,感觉要被刷新三观,实际上是没有的。
利用in-order是sorted的特性按部就班地做就行了。
Iterative:
public class Solution {
public int kthSmallest(TreeNode root, int k) {
Stack<TreeNode> stk = new Stack<>();
TreeNode temp = root;
while (!stk.isEmpty() || temp != null) {
while (temp != null) {
stk.push(temp);
temp = temp.left;
}
temp = stk.pop();
if (--k == 0) {
return temp.val;
}
temp = temp.right;
}
return -1;
}
}
Recursive:
public class Solution {
int res;
int count = 0;
public int kthSmallest(TreeNode root, int k) {
dfs(root, k);
return res;
}
public void dfs(TreeNode root, int k) {
if (root == null) return;
dfs(root.left, k);
if (++count == k) {
res = root.val;
return;
}
dfs(root.right, k);
}
}
2个办法都很基础。。
看了一下Discussion,剽窃到一个用二分的方法,实际情况会比较快。
作者的名字真忘了,光记得他给了3种方法,剩下2种就是上面的2种,他说STACK那个是BFS,其实不是,是DFS。。。
Binary-Search
做到一半觉得不对,这他妈是TOP-DOWN啊,快个鸡巴。。最坏的情况是O(n^2)。。
public class Solution {
public int kthSmallest(TreeNode root, int k) {
int left = getNum(root.left);
if (left + 1 < k) {
return kthSmallest(root.right, k - left - 1);
} else if (left + 1 > k) {
return kthSmallest(root.left, k);
} else {
return root.val;
}
}
public int getNum(TreeNode root) {
if (root == null) return 0;
return getNum(root.left) + getNum(root.right) + 1;
}
}
但是实际binary search这个方法的思路就是题目中follow-up的思路。
二分的时候,我们先算左边,如果左边总数比K小,我们直接去右边找就行了;如果总数比K大,就要去左边重新计算数量,很麻烦,但是如果提前改变结构,每个Node都知道左支有多少个,就不用每次都找了,可以直接判断。
follow-up的答案就是先preprocess the entire tree...这样除了一开始的过程是O(n),用post-order,后来一直是O(Height)