不要被题目迷惑,肯定是要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)
来源:https://www.cnblogs.com/reboot329/p/6103517.html