Given a sorted array arr[] and a value X, find the k closest elements to X in arr[].
Examples:
Input: K = 4, X = 35
arr[] = {12, 16, 22, 30, 35, 39, 42,
45, 48, 50, 53, 55, 56}
Output: 30 39 42 45
Note that if the element is present in array, then it should not be in output, only the other closest elements are required.
In the following solutions, it is assumed that all elements of array are distinct.
A simple solution is to do linear search for k closest elements.
- Start from the first element and search for the crossover point (The point before which elements are smaller than or equal to X and after which elements are greater). This step takes O(n) time.
- Once we find the crossover point, we can compare elements on both sides of crossover point to print k closest elements. This step takes O(k) time.
The time complexity of the above solution is O(n).
An Optimized Solution is to find k elements in O(Logn + k) time. The idea is to use Binary Search to find the crossover point. Once we find index of crossover point, we can print k closest elements in O(k) time.
C++
#include<stdio.h> /* Function to find the cross over point (the point before which elements are smaller than or equal to x and after which greater than x)*/ int findCrossOver( int arr[], int low, int high, int x) { // Base cases if (arr[high] <= x) // x is greater than all return high; if (arr[low] > x) // x is smaller than all return low; // Find the middle point int mid = (low + high)/2; /* low + (high - low)/2 */ /* If x is same as middle element, then return mid */ if (arr[mid] <= x && arr[mid+1] > x) return mid; /* If x is greater than arr[mid], then either arr[mid + 1] is ceiling of x or ceiling lies in arr[mid+1...high] */ if (arr[mid] < x) return findCrossOver(arr, mid+1, high, x); return findCrossOver(arr, low, mid - 1, x); } // This function prints k closest elements to x in arr[]. // n is the number of elements in arr[] void printKclosest( int arr[], int x, int k, int n) { // Find the crossover point int l = findCrossOver(arr, 0, n-1, x); int r = l+1; // Right index to search int count = 0; // To keep track of count of elements already printed // If x is present in arr[], then reduce left index // Assumption: all elements in arr[] are distinct if (arr[l] == x) l--; // Compare elements on left and right of crossover // point to find the k closest elements while (l >= 0 && r < n && count < k) { if (x - arr[l] < arr[r] - x) printf ( "%d " , arr[l--]); else printf ( "%d " , arr[r++]); count++; } // If there are no more elements on right side, then // print left elements while (count < k && l >= 0) printf ( "%d " , arr[l--]), count++; // If there are no more elements on left side, then // print right elements while (count < k && r < n) printf ( "%d " , arr[r++]), count++; } /* Driver program to check above functions */ int main() { int arr[] ={12, 16, 22, 30, 35, 39, 42, 45, 48, 50, 53, 55, 56}; int n = sizeof (arr)/ sizeof (arr[0]); int x = 35, k = 4; printKclosest(arr, x, 4, n); return 0; } |
Java
// Java program to find k closest elements to a given value class KClosest { /* Function to find the cross over point (the point before which elements are smaller than or equal to x and after which greater than x)*/ int findCrossOver( int arr[], int low, int high, int x) { // Base cases if (arr[high] <= x) // x is greater than all return high; if (arr[low] > x) // x is smaller than all return low; // Find the middle point int mid = (low + high)/ 2 ; /* low + (high - low)/2 */ /* If x is same as middle element, then return mid */ if (arr[mid] <= x && arr[mid+ 1 ] > x) return mid; /* If x is greater than arr[mid], then either arr[mid + 1] is ceiling of x or ceiling lies in arr[mid+1...high] */ if (arr[mid] < x) return findCrossOver(arr, mid+ 1 , high, x); return findCrossOver(arr, low, mid - 1 , x); } // This function prints k closest elements to x in arr[]. // n is the number of elements in arr[] void printKclosest( int arr[], int x, int k, int n) { // Find the crossover point int l = findCrossOver(arr, 0 , n- 1 , x); int r = l+ 1 ; // Right index to search int count = 0 ; // To keep track of count of elements // already printed // If x is present in arr[], then reduce left index // Assumption: all elements in arr[] are distinct if (arr[l] == x) l--; // Compare elements on left and right of crossover // point to find the k closest elements while (l >= 0 && r < n && count < k) { if (x - arr[l] < arr[r] - x) System.out.print(arr[l--]+ " " ); else System.out.print(arr[r++]+ " " ); count++; } // If there are no more elements on right side, then // print left elements while (count < k && l >= 0 ) { System.out.print(arr[l--]+ " " ); count++; } // If there are no more elements on left side, then // print right elements while (count < k && r < n) { System.out.print(arr[r++]+ " " ); count++; } } /* Driver program to check above functions */ public static void main(String args[]) { KClosest ob = new KClosest(); int arr[] = { 12 , 16 , 22 , 30 , 35 , 39 , 42 , 45 , 48 , 50 , 53 , 55 , 56 }; int n = arr.length; int x = 35 , k = 4 ; ob.printKclosest(arr, x, 4 , n); } } /* This code is contributed by Rajat Mishra */ |
Python3
# Function to find the cross over point # (the point before which elements are # smaller than or equal to x and after # which greater than x) def findCrossOver(arr, low, high, x) : # Base cases if (arr[high] < = x) : # x is greater than all return high if (arr[low] > x) : # x is smaller than all return low # Find the middle point mid = (low + high) / / 2 # low + (high - low)// 2 # If x is same as middle element, # then return mid if (arr[mid] < = x and arr[mid + 1 ] > x) : return mid # If x is greater than arr[mid], then # either arr[mid + 1] is ceiling of x # or ceiling lies in arr[mid+1...high] if (arr[mid] < x) : return findCrossOver(arr, mid + 1 , high, x) return findCrossOver(arr, low, mid - 1 , x) # This function prints k closest elements to x # in arr[]. n is the number of elements in arr[] def printKclosest(arr, x, k, n) : # Find the crossover point l = findCrossOver(arr, 0 , n - 1 , x) r = l + 1 # Right index to search count = 0 # To keep track of count of # elements already printed # If x is present in arr[], then reduce # left index. Assumption: all elements # in arr[] are distinct if (arr[l] = = x) : l - = 1 # Compare elements on left and right of crossover # point to find the k closest elements while (l > = 0 and r < n and count < k) : if (x - arr[l] < arr[r] - x) : print (arr[l], end = " " ) l - = 1 else : print (arr[r], end = " " ) r + = 1 count + = 1 # If there are no more elements on right # side, then print left elements while (count < k and l > = 0 ) : print (arr[l], end = " " ) l - = 1 count + = 1 # If there are no more elements on left # side, then print right elements while (count < k and r < n) : print (arr[r], end = " " ) r + = 1 count + = 1 # Driver Code if __name__ = = "__main__" : arr = [ 12 , 16 , 22 , 30 , 35 , 39 , 42 , 45 , 48 , 50 , 53 , 55 , 56 ] n = len (arr) x = 35 k = 4 printKclosest(arr, x, 4 , n) # This code is contributed by Ryuga |
C#
// C# program to find k closest elements to // a given value using System; class GFG { /* Function to find the cross over point (the point before which elements are smaller than or equal to x and after which greater than x)*/ static int findCrossOver( int []arr, int low, int high, int x) { // Base cases // x is greater than all if (arr[high] <= x) return high; // x is smaller than all if (arr[low] > x) return low; // Find the middle point /* low + (high - low)/2 */ int mid = (low + high)/2; /* If x is same as middle element, then return mid */ if (arr[mid] <= x && arr[mid+1] > x) return mid; /* If x is greater than arr[mid], then either arr[mid + 1] is ceiling of x or ceiling lies in arr[mid+1...high] */ if (arr[mid] < x) return findCrossOver(arr, mid+1, high, x); return findCrossOver(arr, low, mid - 1, x); } // This function prints k closest elements // to x in arr[]. n is the number of // elements in arr[] static void printKclosest( int []arr, int x, int k, int n) { // Find the crossover point int l = findCrossOver(arr, 0, n-1, x); // Right index to search int r = l + 1; // To keep track of count of elements int count = 0; // If x is present in arr[], then reduce // left index Assumption: all elements in // arr[] are distinct if (arr[l] == x) l--; // Compare elements on left and right of // crossover point to find the k closest // elements while (l >= 0 && r < n && count < k) { if (x - arr[l] < arr[r] - x) Console.Write(arr[l--]+ " " ); else Console.Write(arr[r++]+ " " ); count++; } // If there are no more elements on right // side, then print left elements while (count < k && l >= 0) { Console.Write(arr[l--]+ " " ); count++; } // If there are no more elements on left // side, then print right elements while (count < k && r < n) { Console.Write(arr[r++] + " " ); count++; } } /* Driver program to check above functions */ public static void Main() { int []arr = {12, 16, 22, 30, 35, 39, 42, 45, 48, 50, 53, 55, 56}; int n = arr.Length; int x = 35; printKclosest(arr, x, 4, n); } } // This code is contributed by nitin mittal. |
Javascript
<script> // JavaScript program to find k // closest elements to a given value // Function to find the cross over point // (the point before which elements are // smaller than or equal to x and after // which greater than x) function findCrossOver(arr, low, high, x) { // Base cases if (arr[high] <= x) // x is greater than all return high if (arr[low] > x) // x is smaller than all return low // Find the middle point var mid = (low + high) // 2 // low + (high - low)// 2 // If x is same as middle element, // then return mid if (arr[mid] <= x && arr[mid + 1] > x) return mid // If x is greater than arr[mid], then // either arr[mid + 1] is ceiling of x // or ceiling lies in arr[mid+1...high] if (arr[mid] < x) return findCrossOver(arr, mid + 1, high, x) return findCrossOver(arr, low, mid - 1, x) } // This function prints k closest elements to x // in arr[]. n is the number of elements in arr[] function printKclosest(arr, x, k, n) { // Find the crossover point var l = findCrossOver(arr, 0, n - 1, x) var r = l + 1 // Right index to search var count = 0 // To keep track of count of // elements already printed // If x is present in arr[], then reduce // left index. Assumption: all elements // in arr[] are distinct if (arr[l] == x) l -= 1 // Compare elements on left and right of crossover // point to find the k closest elements while (l >= 0 && r < n && count < k) { if (x - arr[l] < arr[r] - x) { document.write(arr[l] + " " ) l -= 1 } else { document.write(arr[r] + " " ) r += 1 } count += 1 } // If there are no more elements on right // side, then print left elements while (count < k && l >= 0) { print(arr[l]) l -= 1 count += 1 } // If there are no more elements on left // side, then print right elements while (count < k && r < n) { print(arr[r]) r += 1 count += 1 } } // Driver Code var arr = [ 12, 16, 22, 30, 35, 39, 42, 45, 48, 50, 53, 55, 56 ] var n = arr.length var x = 35 var k = 4 printKclosest(arr, x, 4, n) // This code is contributed by AnkThon </script> |
PHP
<?php // PHP Program to Find k closest // elements to a given value /* Function to find the cross over point (the point before which elements are smaller than or equal to x and after which greater than x) */ function findCrossOver( $arr , $low , $high , $x ) { // Base cases // x is greater than all if ( $arr [ $high ] <= $x ) return $high ; // x is smaller than all if ( $arr [ $low ] > $x ) return $low ; // Find the middle point /* low + (high - low)/2 */ $mid = ( $low + $high )/2; /* If x is same as middle element, then return mid */ if ( $arr [ $mid ] <= $x and $arr [ $mid + 1] > $x ) return $mid ; /* If x is greater than arr[mid], then either arr[mid + 1] is ceiling of x or ceiling lies in arr[mid+1...high] */ if ( $arr [ $mid ] < $x ) return findCrossOver( $arr , $mid + 1, $high , $x ); return findCrossOver( $arr , $low , $mid - 1, $x ); } // This function prints k // closest elements to x in arr[]. // n is the number of elements // in arr[] function printKclosest( $arr , $x , $k , $n ) { // Find the crossover point $l = findCrossOver( $arr , 0, $n - 1, $x ); // Right index to search $r = $l + 1; // To keep track of count of // elements already printed $count = 0; // If x is present in arr[], // then reduce left index // Assumption: all elements // in arr[] are distinct if ( $arr [ $l ] == $x ) $l --; // Compare elements on left // and right of crossover // point to find the k // closest elements while ( $l >= 0 and $r < $n and $count < $k ) { if ( $x - $arr [ $l ] < $arr [ $r ] - $x ) echo $arr [ $l --], " " ; else echo $arr [ $r ++], " " ; $count ++; } // If there are no more // elements on right side, // then print left elements while ( $count < $k and $l >= 0) echo $arr [ $l --], " " ; $count ++; // If there are no more // elements on left side, // then print right elements while ( $count < $k and $r < $n ) echo $arr [ $r ++]; $count ++; } // Driver Code $arr = array (12, 16, 22, 30, 35, 39, 42, 45, 48, 50, 53, 55, 56); $n = count ( $arr ); $x = 35; $k = 4; printKclosest( $arr , $x , 4, $n ); // This code is contributed by anuj_67. ?> |
39 30 42 45
Time complexity: O(Logn + k).
Auxiliary Space: O(1), since no extra space has been used.
Approach 2: Using Priority Queue
This approach uses a priority queue (max heap) to maintain the k closest numbers to x. It iterates over the elements in the array and calculates their absolute differences from x. The pairs of absolute differences and negative values are pushed into the max heap. If the size of the max heap exceeds k, the element with the maximum absolute difference is removed. Finally, the top k elements from the max heap are extracted and stored in a result vector. The vector is then reversed to obtain the closest numbers in ascending order before being returned as the result.
Below is the implementation:
C++
#include <bits/stdc++.h> using namespace std; vector< int > findClosestElements(vector< int >& arr, int k, int x) { // Create a max heap to store the pairs of absolute // differences and negative values priority_queue<pair< int , int > > maxH; int n = arr.size(); for ( int i = 0; i < n; i++) { // Skip if the element is equal to x if (arr[i] == x) continue ; // Calculate the absolute difference and add the // pair to the max heap maxH.push({ abs (arr[i] - x), -arr[i] }); // If the size of the max heap exceeds k, remove the // element with the maximum absolute difference if (maxH.size() > k) maxH.pop(); } // Store the result in a vector vector< int > result; // Retrieve the top k elements from the max heap while (!maxH.empty()) { // Get the top element from the max heap auto p = maxH.top(); maxH.pop(); // Add the negative value to the result vector result.push_back(-p.second); } // Reverse the result vector to get the closest numbers // in ascending order reverse(result.begin(), result.end()); return result; } int main() { vector< int > arr = { 12, 16, 22, 30, 35, 39, 42, 45, 48, 50, 53, 55, 56 }; int k = 4, x = 35; vector< int > res = findClosestElements(arr, k, x); for ( int i = 0; i < res.size(); i++) { cout << res[i] << " " ; } cout << endl; return 0; } |
Java
/*package whatever //do not write package name here */ import java.io.*; import java.util.*; class GFG { // Create pair class which implements Comparable // interface static class Pair implements Comparable<Pair> { int absDiff; int ind; Pair( int f, int s) { absDiff = f; ind = s; } public int compareTo(GFG.Pair o) { // If there are two elements with the same // difference with X, the greater element is // given priority. if (absDiff == o.absDiff) return ind - o.ind; else return o.absDiff - absDiff; } } static int [] printKClosest( int [] nums, int n, int k, int x) { PriorityQueue<Pair> maxHeap = new PriorityQueue<>(); for ( int i = 0 ; i < nums.length; i++) { int diff = Math.abs(nums[i] - x); //if nums[i] == x then no need to consider that element if (diff != 0 ) maxHeap.add( new Pair(diff, i)); //if maxheap size exceeds k then remove the element with maximum absolute difference if (maxHeap.size() > k) maxHeap.poll(); } int ans[] = new int [k]; int j = 0 ; while (!maxHeap.isEmpty()) { //Add the remaining elements to the answer ans[j] = nums[maxHeap.poll().ind]; j++; } // reverse the array to get elements closest elements in ascending order for ( int i = 0 ; i < k / 2 ; i++) { int t = ans[i]; ans[i] = ans[k - i - 1 ]; ans[k - i - 1 ] = t; } return ans; } public static void main(String[] args) { int arr[] = { 12 , 16 , 22 , 30 , 35 , 39 , 42 , 45 , 48 , 50 , 53 , 55 , 56 }; int k = 4 , x = 35 ; int ans[] = printKClosest(arr, arr.length, k, x); System.out.println(Arrays.toString(ans)); } } |
Python3
# Python Code for the above approach import heapq def findClosestElements(arr, k, x): # Create a max heap to store the pairs of absolute differences and negative values max_heap = [] for num in arr: # Skip if the element is equal to x if num = = x: continue # Calculate the absolute difference and add the pair to the max heap diff = abs (num - x) heapq.heappush(max_heap, ( - diff, num)) # If the size of the max heap exceeds k, remove the element with the maximum absolute difference if len (max_heap) > k: heapq.heappop(max_heap) # Store the result in an array result = [] # Retrieve the top k elements from the max heap while max_heap: # Get the top element from the max heap diff, num = heapq.heappop(max_heap) # Add the value to the result array result.append(num) # Return the closest numbers in ascending order return sorted (result) # Test case arr = [ 12 , 16 , 22 , 30 , 35 , 39 , 42 , 45 , 48 , 50 , 53 , 55 , 56 ] k = 4 x = 35 res = findClosestElements(arr, k, x) print (res) # THIS CODE IS CONTRIBUTED BY KIRTI AGARWAL |
C#
//C# Code for the above approach using System; using System.Collections.Generic; using System.Linq; class Program { // Function to find the k closest elements to x in the given array static List< int > FindClosestElements(List< int > arr, int k, int x) { // Sort the array by absolute difference from x and then by value arr.Sort((a, b) => Math.Abs(a - x).CompareTo(Math.Abs(b - x)) == 0 ? a.CompareTo(b) : Math.Abs(a - x).CompareTo(Math.Abs(b - x))); // Take the first k elements as they will be the closest var result = arr.GetRange(0, k); return result; } static void Main() { // Test case List< int > arr = new List< int > { 12, 16, 22, 30, 35, 39, 42, 45, 48, 50, 53, 55, 56 }; int k = 4; int x = 35; // Remove the value x from the list before finding the closest elements arr.Remove(x); List< int > res = FindClosestElements(arr, k, x); // Print the result Console.WriteLine( string .Join( " " , res)); } } |
Javascript
function findClosestElements(arr, k, x) { // Create a max heap to store the pairs of absolute // differences and negative values const maxH = new MaxHeap(); const n = arr.length; for (let i = 0; i < n; i++) { // Skip if the element is equal to x if (arr[i] === x) continue ; // Calculate the absolute difference and add the // pair to the max heap const diff = Math.abs(arr[i] - x); maxH.insert({ diff: diff, value: -arr[i] }); // If the size of the max heap exceeds k, remove the // element with the maximum absolute difference if (maxH.size() > k) maxH.extractMax(); } // Store the result in an array const result = []; // Retrieve the top k elements from the max heap while (!maxH.isEmpty()) { // Get the top element from the max heap const p = maxH.extractMax(); // Add the negative value to the result array result.push(-p.value); } // Reverse the result array to get the closest numbers // in ascending order result.reverse(); return result; } // MaxHeap class implementation class MaxHeap { constructor() { this .heap = []; } size() { return this .heap.length; } isEmpty() { return this .heap.length === 0; } insert(value) { this .heap.push(value); this .heapifyUp( this .heap.length - 1); } extractMax() { if ( this .isEmpty()) return null ; const max = this .heap[0]; const lastElement = this .heap.pop(); if (! this .isEmpty()) { this .heap[0] = lastElement; this .heapifyDown(0); } return max; } heapifyUp(index) { const parentIndex = Math.floor((index - 1) / 2); if (parentIndex >= 0 && this .heap[parentIndex].diff < this .heap[index].diff) { this .swap(parentIndex, index); this .heapifyUp(parentIndex); } } heapifyDown(index) { const leftChildIndex = 2 * index + 1; const rightChildIndex = 2 * index + 2; let largestIndex = index; if (leftChildIndex < this .heap.length && this .heap[leftChildIndex].diff > this .heap[largestIndex].diff) { largestIndex = leftChildIndex; } if (rightChildIndex < this .heap.length && this .heap[rightChildIndex].diff > this .heap[largestIndex].diff) { largestIndex = rightChildIndex; } if (largestIndex !== index) { this .swap(largestIndex, index); this .heapifyDown(largestIndex); } } swap(index1, index2) { [ this .heap[index1], this .heap[index2]] = [ this .heap[index2], this .heap[index1]]; } } // Test case const arr = [12, 16, 22, 30, 35, 39, 42, 45, 48, 50, 53, 55, 56]; const k = 4; const x = 35; const res = findClosestElements(arr, k, x); console.log(res); |
39 30 42 45
Time Complexity: O(n log k), where n is the size of the array and k is the number of elements to be returned. The priority queue takes O(log k) time to insert an element and O(log k) time to remove the top element. Therefore, traversing through the array and inserting elements into the priority queue takes O(n log k) time. Popping elements from the priority queue and pushing them into the result vector takes O(k log k) time. Therefore, the total time complexity is O(n log k + k log k) which is equivalent to O(n log k).
Auxiliary Space: O(k), as we are using a priority queue of size k+1 and a vector of size k to store the result.
Exercise: Extend the optimized solution to work for duplicates also, i.e., to work for arrays where elements don’t have to be distinct.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!