272 Closest Binary Search Tree Value II

Given a non-empty binary search tree and a target value, findkvalues in the BST that are closest to the target.

Note:

  • 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.

Example:

Input: root = [4,2,5,1,3], target = 3.714286, and k = 2

    4
   / \
  2   5
 / \
1   3

Output: [4,3]

Follow up: Assume that the BST is balanced, could you solve it in less thanO(n) runtime (wheren= total nodes)?

这题其实延续了270 Closest Binary Search Tree Value的做法,只是把min从一个数换成一个heap。但这解法是T:O(N)。一开还以为可以logN地2分做,然后发现如果k大于半数的话,连另外一边的也得加进去,所以不行。然后下面还贴了O(logN)的解法作为参考,自己是想不出来的了。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> closestKValues(TreeNode root, double target, int k) {
        List<Integer> res = new ArrayList<>();
        if (root == null) {
            return res;
        }

        // find min use maxHeap, keep k cloest in the heap
        PriorityQueue<HeapNode> diffMaxHeap = new PriorityQueue<>((node1, node2) -> node2.diff.compareTo(node1.diff));
        Stack<TreeNode> stack = new Stack<>();        
        TreeNode cur = root;

        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }

            cur = stack.pop();
            double diff = Math.abs(cur.val - target);
            diffMaxHeap.offer(new HeapNode(diff, cur.val));
            if (diffMaxHeap.size() > k) {              
                diffMaxHeap.poll();              
            }             

            cur = cur.right;
        }

        while (!diffMaxHeap.isEmpty()){
            res.add(diffMaxHeap.poll().nodeVal);
        }
        return res;
    }
}

class HeapNode {
    Double diff;
    int nodeVal;

    public HeapNode(Double d, int v) {
        diff = d;
        nodeVal = v;
    }
}

O(logN)的解法:

public class Solution {
    public List<Integer> closestKValues(TreeNode root, double target, int k) {
        List<Integer> ret = new LinkedList<>();
        Stack<TreeNode> succ = new Stack<>();
        Stack<TreeNode> pred = new Stack<>();
        initializePredecessorStack(root, target, pred);
        initializeSuccessorStack(root, target, succ);
        if(!succ.isEmpty() && !pred.isEmpty() && succ.peek().val == pred.peek().val) {
            getNextPredecessor(pred);
        }
        while(k-- > 0) {
            if(succ.isEmpty()) {
                ret.add(getNextPredecessor(pred));
            } else if(pred.isEmpty()) {
                ret.add(getNextSuccessor(succ));
            } else {
                double succ_diff = Math.abs((double)succ.peek().val - target);
                double pred_diff = Math.abs((double)pred.peek().val - target);
                if(succ_diff < pred_diff) {
                    ret.add(getNextSuccessor(succ));
                } else {
                    ret.add(getNextPredecessor(pred));
                }
            }
        }
        return ret;
    }

    private void initializeSuccessorStack(TreeNode root, double target, Stack<TreeNode> succ) {
        while(root != null) {
            if(root.val == target) {
                succ.push(root);
                break;
            } else if(root.val > target) {
                succ.push(root);
                root = root.left;
            } else {
                root = root.right;
            }
        }
    }

    private void initializePredecessorStack(TreeNode root, double target, Stack<TreeNode> pred) {
        while(root != null){
            if(root.val == target){
                pred.push(root);
                break;
            } else if(root.val < target){
                pred.push(root);
                root = root.right;
            } else{
                root = root.left;
            }
        }
    }

    private int getNextSuccessor(Stack<TreeNode> succ) {
        TreeNode curr = succ.pop();
        int ret = curr.val;
        curr = curr.right;
        while(curr != null) {
            succ.push(curr);
            curr = curr.left;
        }
        return ret;
    }

    private int getNextPredecessor(Stack<TreeNode> pred) {
        TreeNode curr = pred.pop();
        int ret = curr.val;
        curr = curr.left;
        while(curr != null) {
            pred.push(curr);
            curr = curr.right;
        }
        return ret;
    }
}

// cleaner version
class Solution {
public List closestKValues(TreeNode root, double target, int k) {

    Stack<TreeNode> succ = new Stack<>();
    Stack<TreeNode> pred = new Stack<>();

    inOrderTraversal(root,false,target,succ);
    inOrderTraversal(root,true,target,pred);

    List<Integer> result = new ArrayList<>();

    for(int i = 0; i<k; i++){
        if(succ.size()==0){
            result.add(getNext(pred,true));
        }else if(pred.size()==0){
            result.add(getNext(succ,false));
        }else{
            if(Math.abs(target-succ.peek().val)<Math.abs(target-pred.peek().val)){
                result.add(getNext(succ,false));
            }else{
                result.add(getNext(pred,true));
            }
        }
    }

    return result;


}

private void inOrderTraversal(TreeNode root, boolean reverse, double target, Stack stack){
    while(root != null){
        if((!reverse && root.val>=target) || (reverse && root.val<target)){
            stack.push(root);
            root = reverse?root.right:root.left;
        }else{
            root = reverse?root.left:root.right;
        }
    }
}

private Integer getNext(Stack<TreeNode> stack, boolean reverse){
    TreeNode curr = stack.pop();
    Integer val = curr.val;
    curr = reverse?curr.left:curr.right;
    while(curr!=null){
        stack.push(curr);
        curr = reverse? curr.right: curr.left;
    }
    return val;
}
}

Last updated