Closest Binary Search Tree Value II

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;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值