272. 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.
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.
先帖priorityQueue的解法

class Solution{
double target;
public List closestKValues(TreeNode root, double target, int k) {
    this.target = target;
    Queue queue = new PriorityQueue<>(new Comparator(){
    public int compare(TreeNode node1, TreeNode node2) {
        if (Math.abs(node1.val - target) != Math.abs(node2.val -target)) {
    return Math.abs(node1.val - target) > Math.abs(node2.val -target) ? -1 : 1;
    }
    return 0;
    })};
    traverse(root, target, k, queue);
    List ans = new ArrayList<>();
    while (!queue.isEmpty()) {
    ans.add(queue.poll().val);
    }
    return ans;
}
private void traverse(TreeNode node, double target, int k, Queue queue) {
    if (node == null) return;
    if (queue.size() < k) {
        queue.offer(node);
  } else {
    if (Math.abs(node.val - target) < Math.abs(queue.peek().val - target)) {
        queue.poll();
        queue.offer(node);
        }
  }
    traverse(node.left, target, k, queue);
    traverse(node.right, target, k, queue);
}

}

再帖Deque的解法

class Solution {
    public List closestKValues(TreeNode root, double target, int k) {
        Deque deque = new ArrayDeque<>();
        traverse(root, target, k, deque);
        List ans = new ArrayList<>();
        while (!deque.isEmpty()) ans.add(deque.pollFirst());
            return ans;
    }
    private void traverse(TreeNode root, double target, int k, Deque deque) {
        if (root == null) return;
        traverse(root.left, target, k, deque);
        if (deque.size() < k) deque.offerLast(root.val);
        else {
            if (Math.abs(root.val - target) < Math.abs(deque.peekFirst() - target))         {
                deque.offerLast(root.val);
                deque.pollFirst();
                } else return;
            }
        traverse(root.right, target, k, deque);
    }
}

这题很难的地方是follow up要求要用少于O(N)的复杂度。
其实就是建两个iterator,一个是小的,一个是大的,然后分别从两个iterator取值,谁离的近就用谁的。一直取到 k。
Iterator的写法较有意思,以前没写过。
这是BST的一个特有的性质,可以写从一个点出发递增和从一个点出发递减的iterator。这个好赞。
形像的表述一下。我在一条从上到下的河流里穿梭,我根据node.val来确定我的航向。如果node.val比我target要小,相当于我从这个node的右边驶过,我的小船就往右驶。如果node.val比我target大,相当于我从这个node的左边驶过,我的小船继续往左开。我同时记下那些我经过的点,这些点是我以后回来的入口。如果 node.val比我的值小,那就是predecessor的一员。如果比我大,那就是successor的一员。
如果node.val正好是我的target, 那我的successor/predecessor里面取等号的那个已经满足了, 我只需要再找那个没等号的那个。
下面看代码

class Solution {
    public List closestKValues(TreeNode root, double target, int k) {
        Deque successor = new LinkedList<>();
        Deque predecessor = new LinkedList<>();
        TreeNode cur = root;
        while (cur != null) {
            if (target <= cur.val) {
                successor.push(cur);
                cur = cur.left;
            } else {
                predecessor.push(cur);
                cur = cur.right;
            }
        }
        List ans = new ArrayList<>();
        while (ans.size() < k) {
            Integer a = peek(successor);
            Integer b = peek(predecessor);
            if (a == null) a = Integer.MAX_VALUE;
            if (b == null) b = Integer.MIN_VALUE;
            double diffA = Math.abs(a * 1.0 - target);
            double diffB = Math.abs(b * 1.0 - target);
            if (diffA < diffB) {
                ans.add(a);
                pollSuccessor(successor);
            } else {
                ans.add(b);
                pollPredecessor(predecessor);
            }
        }
        return ans;
    }
    private Integer peek(Deque successor) {
        if (successor.isEmpty()) return null;
        return successor.peek().val;
    }
    private void pollSuccessor(Deque successor) {
        TreeNode node = successor.pop().right;
        while (node != null) {
            successor.push(node);
            node = node.left;
        }
    }
    private void pollPredecessor(Deque predecessor) {
        TreeNode node = predecessor.pop().left;
        while (node != null) {
            predecessor.push(node);
            node = node.right;
        }
    }
}

上面那个代码虽然很短,但是实现的时候不是很好套套路,不容易掌握,掌握了价值也不是很大。
所以最好是单建一个descendingIterator, 和asscendingIterator的类
这样代码长是长了一点, 不过都是基本操作,好实现, 逻辑清楚,易于维护。
见下面

class Solution {
    public List closestKValues(TreeNode root, double target, int k) {
        DescendingIterator dIter = new DescendingIterator(root, target);
        AsscendingIterator aIter = new AsscendingIterator(root, target);
        List ans = new ArrayList<>();
        for (int i = 0; i < k ;i++) {
            Integer dn = dIter.peek();
            Integer an = aIter.peek();
            if (dn == null) ans.add(aIter.poll());
            else if (an == null) ans.add(dIter.poll());
            else {
                if (target - dn < an - target)  ans.add(dIter.poll());
                else ans.add(aIter.poll());
            }
        }
        return ans;
    }
}
class DescendingIterator {
    Deque deque;
    public DescendingIterator(TreeNode root, double target){
        // lesser
        deque = new ArrayDeque<>();
        while (root != null) {
            if (root.val >= target) {
                root = root.left;
            } else {
                deque.push(root);
                root = root.right;
            }
        }
    }
    public Integer peek() {
        if (deque.isEmpty()) return null;
        return deque.peek().val;
    }
    public Integer poll() {
        TreeNode node = deque.pop();
        int ans = node.val;
        if (node.left != null) {
            node = node.left;
            while (node != null) {
                deque.push(node);
                node = node.right;
            }
        }
        return ans;
    }
}

class AsscendingIterator {
    Deque deque;
    public AsscendingIterator(TreeNode root, double target){
        // greater or equals
        deque = new ArrayDeque<>();
        while (root != null) {
            if (root.val == target) {
                deque.push(root);
                break;
            } else if (root.val < target) {
                root = root.right;
            } else {
                deque.push(root);
                root = root.left;
            }
        }
    }
    public Integer peek() {
        if (deque.isEmpty()) return null;
        return deque.peek().val;
    }
    public Integer poll() {
        TreeNode node = deque.pop();
        int ans = node.val;
        if (node.right != null) {
            node = node.right;
            while (node != null) {
                deque.push(node);
                node = node.left;
            }
        }
        return ans;
    }
}

你可能感兴趣的:(272. Closest Binary Search Tree Value II)