11package  com .leetcode .trees ;
22
3+ import  java .util .LinkedList ;
4+ import  java .util .List ;
5+ import  java .util .Queue ;
6+ import  java .util .Stack ;
7+ 
38import  static  org .junit .jupiter .api .Assertions .assertEquals ;
49
510/** 
611 * Level: Hard 
712 * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value-ii/ 
813 * Problem Description: 
14+  * Given a non-empty binary search tree and a target value, find k values in the BST that are closest to the target. 
15+  * 
16+  * Note: 
17+  * - Given target value is a floating point. 
18+  * - You may assume k is always valid, that is: k ≤ total nodes. 
19+  * - You are guaranteed to have only one unique set of k values in the BST that are closest to the target. 
20+  * 
21+  * Example: 
22+  * Input: root = [4,2,5,1,3], target = 3.714286, and k = 2 
923 * 
24+  *     4 
25+  *    / \ 
26+  *   2   5 
27+  *  / \ 
28+  * 1   3 
29+  * 
30+  * Output: [4,3] 
31+  * 
32+  * Follow up: 
33+  * Assume that the BST is balanced, could you solve it in less than O(n) runtime (where n = total nodes)? 
1034 * 
1135 * @author rampatra 
1236 * @since 2019-07-31 
1337 */ 
1438public  class  ClosestBinarySearchTreeValueII  {
1539
40+ 
41+     /** 
42+      * The idea is simple. We do the inorder traversal and keep the values less than or equal to target in a stack and 
43+      * the values greater than target in a queue. And finally, we compare values from both stack and queue and take 
44+      * whichever is the closest to target value each time. 
45+      * 
46+      * Note: We can optimize it even further in terms of space. We can get rid of the stack and queue and just fill up 
47+      * the result list in the recursive inOrder call. Once the result list is of size k, we can compare and remove the 
48+      * farthest value and insert the closer value. See {@link ClosestBinarySearchTreeValueII#closestKValuesOptimized(TreeNode, double, int)}. 
49+      * 
50+      * @param root 
51+      * @param target 
52+      * @param k 
53+      * @return 
54+      */ 
55+     public  static  List <Integer > closestKValues (TreeNode  root , double  target , int  k ) {
56+         int  count  = 0 ;
57+         List <Integer > closestKValues  = new  LinkedList <>();
58+ 
59+         Stack <Integer > predecessors  = new  Stack <>();
60+         Queue <Integer > successors  = new  LinkedList <>();
61+         inOrder (root , predecessors , successors , target , k );
62+ 
63+         while  (count  < k ) {
64+             if  (predecessors .empty ()) {
65+                 closestKValues .add (successors .poll ());
66+             } else  if  (successors .isEmpty ()) {
67+                 closestKValues .add (predecessors .pop ());
68+             } else  if  (Math .abs (target  - predecessors .peek ()) < Math .abs (target  - successors .peek ())) {
69+                 closestKValues .add (predecessors .pop ());
70+             } else  {
71+                 closestKValues .add (successors .poll ());
72+             }
73+             count ++;
74+         }
75+ 
76+         return  closestKValues ;
77+     }
78+ 
79+     private  static  void  inOrder (TreeNode  root , Stack <Integer > predecessors , Queue <Integer > successors , double  target , int  k ) {
80+         if  (root  == null  || successors .size () == k ) return ;
81+         inOrder (root .left , predecessors , successors , target , k );
82+         if  (root .val  <= target ) {
83+             predecessors .add (root .val );
84+         } else  {
85+             successors .add (root .val );
86+         }
87+         inOrder (root .right , predecessors , successors , target , k );
88+     }
89+ 
90+ 
1691    /** 
17-      * @param node 
18-      * @param parentNode 
19-      * @param val 
20-      * @param diff 
92+      * This approach is similar to the above one but it doesn't use stack or queue. 
93+      * 
94+      * @param root 
95+      * @param target 
96+      * @param k 
2197     * @return 
2298     */ 
23-     public  static  TreeNode  findNodeWithClosestValue (TreeNode  node , TreeNode  parentNode , int  val , int  diff ) {
24-         return  null ;
99+     public  static  List <Integer > closestKValuesOptimized (TreeNode  root , double  target , int  k ) {
100+         LinkedList <Integer > closestKValues  = new  LinkedList <>();
101+         inOrder (root , target , k , closestKValues );
102+         return  closestKValues ;
103+     }
104+ 
105+     private  static  void  inOrder (TreeNode  root , double  target , int  k , LinkedList <Integer > closestKValues ) {
106+         if  (root  == null ) return ;
107+ 
108+         inOrder (root .left , target , k , closestKValues );
109+         if  (closestKValues .size () == k ) {
110+             //if size k, add current and remove head if it's closer to target, otherwise return 
111+             if  (Math .abs (target  - root .val ) < Math .abs (target  - closestKValues .peekFirst ()))
112+                 closestKValues .removeFirst ();
113+             else  {
114+                 return ;
115+             }
116+         }
117+         closestKValues .add (root .val );
118+         inOrder (root .right , target , k , closestKValues );
25119    }
26120
27121    public  static  void  main (String [] args ) {
@@ -46,13 +140,8 @@ public static void main(String[] args) {
46140        root .left .left .right  = new  TreeNode (6 );
47141        root .right .right  = new  TreeNode (20 );
48142
49-         assertEquals (13 , findNodeWithClosestValue (root , root , 15 , Integer .MAX_VALUE ).val );
50-         assertEquals (13 , findNodeWithClosestValue (root , root , 13 , Integer .MAX_VALUE ).val );
51-         assertEquals (9 , findNodeWithClosestValue (root , root , 9 , Integer .MAX_VALUE ).val );
52-         assertEquals (2 , findNodeWithClosestValue (root , root , 2 , Integer .MAX_VALUE ).val );
53-         assertEquals (2 , findNodeWithClosestValue (root , root , 1 , Integer .MAX_VALUE ).val );
54-         assertEquals (6 , findNodeWithClosestValue (root , root , 6 , Integer .MAX_VALUE ).val );
55-         assertEquals (13 , findNodeWithClosestValue (root , root , 11 , Integer .MAX_VALUE ).val ); // tie b/w 9 and 13 
143+         assertEquals ("[9, 8, 7, 6, 5]" , closestKValues (root , 8.5 , 5 ).toString ());
144+         assertEquals ("[5, 6, 7, 8, 9]" , closestKValuesOptimized (root , 8.5 , 5 ).toString ());
56145
57146        /* 
58147            BST looks like: 
@@ -67,10 +156,11 @@ public static void main(String[] args) {
67156        root .left  = new  TreeNode (7 );
68157        root .right  = new  TreeNode (13 );
69158        root .left .left  = new  TreeNode (5 );
70-         root .left .right  = new  TreeNode (8 );
71159        root .right .left  = new  TreeNode (13 );
160+         root .left .right  = new  TreeNode (8 );
72161        root .right .right  = new  TreeNode (20 );
73162
74-         assertEquals (13 , findNodeWithClosestValue (root , root , 15 , Integer .MAX_VALUE ).val );
163+         assertEquals ("[13, 13, 9, 20, 8]" , closestKValues (root , 14 , 5 ).toString ());
164+         assertEquals ("[8, 9, 13, 13, 20]" , closestKValuesOptimized (root , 14 , 5 ).toString ());
75165    }
76166}
0 commit comments