Given a non-empty binary search tree and a target value, find k
values in the BST that are closest to the target.
Example
Example 1:
Input:
{1}
0.000000
1
Output:
[1]
Explanation:
Binary tree {1}, denote the following structure:
1
Example 2:
Input:
{3,1,4,#,2}
0.275000
2
Output:
[1,2]
Explanation:
Binary tree {3,1,4,#,2}, denote the following structure:
3
/ \
1 4
\
2
Challenge
Assume that the BST is balanced, could you solve it in less than O(n) runtime (where n = total nodes)?
Notice
- Given target value is a floating point.
- You may assume
k
is always valid, that is:k ≤ total
nodes. - You are guaranteed to have only one
unique
set of k values in the BST that are closest to the target.
思路:这题考察的很多,不亏是google的题目。其实想明白了很简单,就是:inorder travel的stack方法如果会写的话,怎么找target临近的k个值,也就是用个queue来找。
因为inorder travel得到的值的是从小到大的值,所以就相当于在一个连续的array里面找target 附近的k个值,那么就用一个queue来存储这k个值,然后每次加进来的值,跟queue头的元素,进行比较,如果 math.abs(node.val - target) < Math.abs(queue.peek().val - target) node和target的距离比queue头元素与target的距离要小,说明queue头是比node要小的,所以poll头元素,将新的node加入队列尾部,然后继续移动,如果哪次新加进来的node与target距离比头元素与target距离还要大,那么直接break掉,因为后面的node距离只可能更大,因为我们是inorder travel。有时候,觉得google的题,只要掌握了基本的算法和原理,稍微拐弯一下就可以想到更好的解法,这就是google的题目的优点,特别具有区分度。不难,大家都可以做,但是做出来都不一样。O(n);
class Solution {
public List<Integer> closestKValues(TreeNode root, double target, int k) {
LinkedList<Integer> list = new LinkedList<>();
dfs(root, list, target, k);
return list;
}
private void dfs(TreeNode root, LinkedList<Integer> list, double target, int k) {
if(root == null) {
return;
}
dfs(root.left, list, target, k);
if(list.size() == k) {
if(Math.abs(list.peekFirst() - target) > Math.abs(root.val - target)) {
list.pollFirst();
} else {
return;
}
}
list.add(root.val);
dfs(root.right, list, target, k);
}
}
class Solution {
public List<Integer> closestKValues(TreeNode root, double target, int k) {
Stack<TreeNode> stack = new Stack<>();
LinkedList<Integer> list = new LinkedList<>();
pushLeft(root, stack);
while(!stack.isEmpty()) {
TreeNode node = stack.pop();
if(list.size() < k) {
list.add(node.val);
} else {
if(Math.abs(list.peekFirst() - target) > Math.abs(node.val - target)) {
list.pollFirst();
list.offer(node.val);
} else {
break;
}
}
if(node.right != null) {
pushLeft(node.right, stack);
}
}
return list;
}
private void pushLeft(TreeNode node, Stack<TreeNode> stack) {
while(node != null) {
stack.push(node);
node = node.left;
}
}
}
思路2:O(logn + k); 分别用prestack和nextstack,来记录找到target过程中的点,然后根据diff来进行 next++, pre--的操作,这里涉及到inorder的next和pre的写法,next就是stack push 右边left的点,反过来,pre就是stack push左边 right的点;
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> closestKValues(TreeNode root, double target, int k) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> prestack = new Stack<>();
Stack<TreeNode> nextstack = new Stack<>();
TreeNode node = root;
// node在target的左边就是prestack,在target的右边就是nextstack;
while(node != null) {
if(node.val < target) {
prestack.push(node);
node = node.right;
} else {
// node.val > target;
nextstack.push(node);
node = node.left;
}
}
int count = 0;
while(count < k) {
double prediff = prestack.isEmpty() ? Double.MAX_VALUE : Math.abs(prestack.peek().val - target);
double nextdiff = nextstack.isEmpty() ? Double.MAX_VALUE: Math.abs(nextstack.peek().val - target);
if(prediff < nextdiff) {
list.add(prestack.peek().val);
goPre(prestack);
count++;
} else {
// prediff > nextdiff;
list.add(nextstack.peek().val);
goNext(nextstack);
count++;
}
}
return list;
}
// 先写nextstack,那么prestack就是next stack反过来写;
private void goNext(Stack<TreeNode> nextstack) {
TreeNode node = nextstack.pop();
if(node.right != null) {
node = node.right;
while(node != null) {
nextstack.push(node);
node = node.left;
}
}
}
private void goPre(Stack<TreeNode> prestack) {
TreeNode node = prestack.pop();
if(node.left != null) {
node = node.left;
while(node != null) {
prestack.push(node);
node = node.right;
}
}
}
}