Open In App

Find K closest elements to given Value in Unsorted Array

Last Updated : 30 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given an unsorted array arr[] and two numbers X and K, the task is to find K closest values to X in arr[].

Examples: 

Input: arr[] = {10, 2, 14, 4, 7, 6}, X = 5, K = 3 
Output: 4 6 7
Explanation: Three closest values of x are 4, 6 and 7.

Input: arr[] = {-10, -50, 20, 17, 80}, X = 20, K = 2
Output: 17 20

Recommended Practice

Find K closest Element by Sorting the Array: 

The simple idea is to sort the array. Then apply the method discussed to K closest values in a sorted array.

Find K closest Element using Heap:

An efficient approach is to use a max heap data structure of size K

Find the absolute difference of the array elements with X and push them in the heap. If at any position the heap gets filled then only push elements when it has an absolute difference less than the first element of the max heap.

Follow the steps mentioned below to implement the idea:

  • Build a max heap of size K.
  • Initially push the first K elements of the array with their absolute difference from X.
  • Now traverse from K+1 to N:
    • If the absolute difference is less than the maximum difference stored in the heap, then remove the maximum difference and insert the current difference.
  • After the traversal is over, the K elements stored in the heap are the required K closest elements. 

Below is the implementation of the above approach. 

C++




// C++ program to find k closest elements
  
#include <bits/stdc++.h>
using namespace std;
  
// Function to find the K closest elements
void printKclosest(int arr[], int n, int x,
                   int k)
{
    // Make a max heap of difference with
    // first k elements.
    priority_queue<pair<int, int> > pq;
    for (int i = 0; i < k; i++)
        pq.push({ abs(arr[i] - x), i });
  
    // Now process remaining elements.
    for (int i = k; i < n; i++) {
  
        int diff = abs(arr[i] - x);
  
        // If difference with current
        // element is more than root,
        // then ignore it.
        if (diff > pq.top().first)
            continue;
  
        // Else remove root and insert
        pq.pop();
        pq.push({ diff, i });
    }
  
    // Print contents of heap.
    while (pq.empty() == false) {
        cout << arr[pq.top().second] << " ";
        pq.pop();
    }
}
  
// Driver code
int main()
{
    int arr[] = { -10, -50, 20, 17, 80 };
    int X = 20, K = 2;
    int N = sizeof(arr) / sizeof(arr[0]);
      
    // Function call
    printKclosest(arr, N, X, K);
    return 0;
}


Java




// Java program to find k closest elements
  
import java.util.Comparator;
import java.util.PriorityQueue;
  
class Pair {
    Integer key;
    Integer value;
  
    public Pair(Integer key, Integer value)
    {
        this.key = key;
        this.value = value;
    }
    public Integer getKey() { 
        return key; 
    }
    public void setKey(Integer key) { 
        this.key = key; 
    }
    public Integer getValue() { 
        return value; 
    }
    public void setValue(Integer value)
    {
        this.value = value;
    }
}
  
class GFG {
  
    public static void printKclosest(int[] arr, int n,
                                     int x, int k)
    {
        // Make a max heap.
        PriorityQueue<Pair> pq
            = new PriorityQueue<>(new Comparator<Pair>() {
                  public int compare(Pair p1, Pair p2)
                  {
                      return p2.getValue().compareTo(
                          p1.getValue());
                  }
              });
  
        // Build heap of difference with
        // first k elements
        for (int i = 0; i < k; i++) {
            pq.offer(
                new Pair(arr[i], Math.abs(arr[i] - x)));
        }
  
        // Now process remaining elements.
        for (int i = k; i < n; i++) {
            int diff = Math.abs(arr[i] - x);
  
            // If difference with current
            // element is more than root,
            // then ignore it.
            if (diff > pq.peek().getValue())
                continue;
  
            // Else remove root and insert
            pq.poll();
            pq.offer(new Pair(arr[i], diff));
        }
  
        // Print contents of heap.
        while (!pq.isEmpty()) {
            System.out.print(pq.poll().getKey() + " ");
        }
    }
  
    // Driver code
    public static void main(String[] args)
    {
        int arr[] = { -10, -50, 20, 17, 80 };
        int X = 20, K = 2;
        int N = arr.length;
  
        printKclosest(arr, N, X, K);
    }
}
  
// This code is contributed by Ashok Borra


Python3




# Python3 program to find k closest elements 
  
import math
import sys
from queue import PriorityQueue
  
# Function to find the K closest elements
def printKclosest(arr,n,x,k):
  
    # Make a max heap of difference with 
    # first k elements. 
    pq = PriorityQueue()
    for i in range(k):
        pq.put((-abs(arr[i]-x),i))
  
    # Now process remaining elements
    for i in range(k,n):
        diff = abs(arr[i]-x)
        p,pi = pq.get()
        curr = -p
  
        # If difference with current 
        # element is more than root, 
        # then put it back. 
        if diff>curr:
            pq.put((-curr,pi))
            continue
        else:
  
            # Else remove root and insert
            pq.put((-diff,i))
              
    # Print contents of heap.
    while(not pq.empty()):
        p,q = pq.get()
        print("{} ".format(arr[q]),end = "")
  
# Driver code
if __name__ == '__main__':
    arr = [-10,-50,20,17,80]
    X, K = 20,2
    N = len(arr)
    printKclosest(arr, N, X, K)


C#




// C# program to find k closest elements
  
using System;
using System.Collections.Generic;
  
class GFG {
  
    // Function to find the K closest elements
    static void printKclosest(int[] arr, int n, int x,
                              int k)
    {
        // Make a max heap of difference with
        // first k elements.
        List<Tuple<int, int> > pq
            = new List<Tuple<int, int> >();
        for (int i = 0; i < k; i++) {
            pq.Add(new Tuple<int, int>(Math.Abs(arr[i] - x),
                                       i));
        }
  
        pq.Sort();
        pq.Reverse();
  
        // Now process remaining elements.
        for (int i = k; i < n; i++) {
  
            int diff = Math.Abs(arr[i] - x);
  
            // If difference with current
            // element is more than root,
            // then ignore it.
            if (diff > pq[0].Item1)
                continue;
  
            // Else remove root and insert
            pq.RemoveAt(0);
            pq.Add(new Tuple<int, int>(diff, i));
            pq.Sort();
            pq.Reverse();
        }
  
        // Print contents of heap.
        while (pq.Count > 0) {
            Console.Write(arr[pq[0].Item2] + " ");
            pq.RemoveAt(0);
        }
    }
  
    // Driver code
    static void Main()
    {
        int[] arr = { -10, -50, 20, 17, 80 };
        int X = 20, K = 2;
        int N = arr.Length;
        printKclosest(arr, N, X, K);
    }
}
  
// This code is contributed by divyesh072019.


Javascript




// Function to find the K closest elements
function printKclosest(arr, x, k) {
      
    // Make a max heap of difference with
     // first k elements.
    const pq = [];
  
    for (let i = 0; i < k; i++) {
        pq.push([Math.abs(arr[i] - x), i]);
    }
  
    pq.sort((a, b) => b[0] - a[0]);
  
// Now process remaining elements.
    for (let i = k; i < arr.length; i++) {
        const diff = Math.abs(arr[i] - x);
  
      // If difference with current
      // element is more than root,
      // then ignore it.
        if (diff > pq[0][0]) {
            continue;
        }
  
        pq.shift();
        pq.push([diff, i]);
        pq.sort((a, b) => b[0] - a[0]);
    }
  
  // Print contents of heap.
    while (pq.length > 0) {
        console.log(arr[pq[0][1]]);
        pq.shift();
    }
}
  
const arr = [-10, -50, 20, 17, 80];
const X = 20;
const K = 2;
printKclosest(arr, X, K);


Output

17 20 








Time Complexity: O(N * logK)
Auxiliary Space: O(K)

Another Approach: Sorting and using Sliding Window

  • Sort the array using any fast sorting algorithm.
  • The problem can be solved by below 3 cases:
    • Case 1(x<=first element of arr]): return the first k elements.
    • Case 2(x>=last element of arr): return the last k elements
    • Case 3(otherwise): create an auxiliary array which will store |arr[i] – x|, Now use sliding window approach to find the first k consecutive elements with least sum, return the elements of the window as the answer.

Below is the implementation of the above approach:

C++




#include<bits/stdc++.h>
using namespace std;
  
vector<int> Kclosest(vector<int> &arr, int x, int k) {
    // Sort the array
    sort(arr.begin(), arr.end());
    vector<int> result;
      
    // If x is less than the first element
    if (x < arr[0]) {
        result.assign(arr.begin(), arr.begin() + k);
        return result;
    }
      
    // If x is greater than the last element
    if (x > arr[arr.size() - 1]) {
        result.assign(arr.end() - k, arr.end());
        return result;
    }
  
    // Compute the absolute differences and store in aux array
    vector<int> aux;
    for (int ele : arr) {
        int diff = abs(ele - x);
        aux.push_back(diff);
    }
  
    int i = 0, j = 0, s = 0, maxi_s = INT_MAX;
    int start = 0, end = 0;
  
    // Find the window with the smallest sum
    while (j < aux.size()) {
        s += aux[j];
        if ((j - i + 1) < k) {
            j++;
        } else if ((j - i + 1) == k) {
            if (s < maxi_s) {
                maxi_s = s;
                start = i;
                end = j;
            }
            s -= aux[i];
            i++;
            j++;
        }
    }
  
    // Store the K closest elements in the result vector
    result.assign(arr.begin() + start, arr.begin() + end + 1);
    return result;
}
  
int main() {
    vector<int> arr = {-10, -50, 20, 17, 80};
    int k = 2;
    int x = 20;
      
    vector<int> result = Kclosest(arr, x, k);
      
    cout << "[" ;
    for (int ele : result) {
        cout << ele << ",";
    }
    cout << "]" ;
      
    return 0;
}
  
// code is contributed by shinjanpatra


Java




import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
  
public class Main {
  
    public static List<Integer> Kclosest(List<Integer> arr, int x, int k) {
        // Sort the array
        arr.sort(null);
        List<Integer> result = new ArrayList<>();
  
        // If x is less than the first element
        if (x < arr.get(0)) {
            result.addAll(arr.subList(0, k));
            return result;
        }
  
        // If x is greater than the last element
        if (x > arr.get(arr.size() - 1)) {
            result.addAll(arr.subList(arr.size() - k, arr.size()));
            return result;
        }
  
        // Compute the absolute differences and store in aux array
        List<Integer> aux = new ArrayList<>();
        for (int ele : arr) {
            int diff = Math.abs(ele - x);
            aux.add(diff);
        }
  
        int i = 0, j = 0, s = 0, maxi_s = Integer.MAX_VALUE;
        int start = 0, end = 0;
  
        // Find the window with the smallest sum
        while (j < aux.size()) {
            s += aux.get(j);
            if ((j - i + 1) < k) {
                j++;
            } else if ((j - i + 1) == k) {
                if (s < maxi_s) {
                    maxi_s = s;
                    start = i;
                    end = j;
                }
                s -= aux.get(i);
                i++;
                j++;
            }
        }
  
        // Store the K closest elements in the result list
        result.addAll(arr.subList(start, end + 1));
        return result;
    }
  
  // Driver Code
    public static void main(String[] args) {
      // input
        List<Integer> arr = Arrays.asList(-10, -50, 20, 17, 80);
        int k = 2;
        int x = 20;
  
        List<Integer> result = Kclosest(new ArrayList<>(arr), x, k);
  
      // output
        System.out.print("[");
        for (int ele : result) {
            System.out.print(ele + ",");
        }
        System.out.print("]");
    }
}


Python




import math
def Kclosest(arr, x, k):
    # Sort the array
    arr.sort() 
    # if x lies beyond arr[0]
    if x < arr[0]:
        arr = arr[:k]
        return arr
    # if x lies beyond arr[-1]
    elif x > arr[-1]:
        arr = arr[len(arr)-k:]
        return arr
    # Apply sliding window on the aux array
    elif x >= arr[0] and x <= arr[-1]:
        aux = []
        for ele in arr:
            diff = int(math.fabs(ele - x))
            aux.append(diff)
        i = 0
        j = 0
        s = 0
        maxi_s = float("inf")
        # find window with smallest sum
        while j < len(aux):
            s += aux[j]
            if (j - i + 1) < k:
                j += 1
            elif (j - i + 1) == k:
                if s < maxi_s:
                    maxi_s = s
                    start = i
                    end = j
                s -= aux[i]
                i += 1
                j += 1
        # Just reutrn the first window with smallest sum 
        arr = arr[start:end+1]
        return arr
          
arr = [-10, -50, 20, 17, 80
k = 2
x = 20
print(Kclosest(arr, x, k))
# This code is contributed by Swagato Chakraborty (swagatochakraborty123)


C#




using System;
using System.Collections.Generic;
using System.Linq;
  
class Program
{
    // Function to find the K closest elements to a given value x in a sorted array arr
    static List<int> Kclosest(List<int> arr, int x, int k)
    {
        // Sort the array
        arr.Sort();
        List<int> result = new List<int>();
  
        // If x is less than the first element
        if (x < arr[0])
        {
            // Take the first k elements as they are the closest
            result.AddRange(arr.Take(k));
            return result;
        }
  
        // If x is greater than the last element
        if (x > arr[arr.Count - 1])
        {
            // Take the last k elements as they are the closest
            result.AddRange(arr.Skip(arr.Count - k));
            return result;
        }
  
        // Compute the absolute differences and store in aux array
        List<int> aux = new List<int>();
        foreach (int ele in arr)
        {
            int diff = Math.Abs(ele - x);
            aux.Add(diff);
        }
  
        int i = 0, j = 0, s = 0, maxi_s = int.MaxValue;
        int start = 0;
  
        // Find the window with the smallest sum
        while (j < aux.Count)
        {
            s += aux[j];
            if ((j - i + 1) < k)
            {
                j++;
            }
            else if ((j - i + 1) == k)
            {
                if (s < maxi_s)
                {
                    maxi_s = s;
                    start = i;
                }
                s -= aux[i];
                i++;
                j++;
            }
        }
  
        // Store the K closest elements in the result list
        result.AddRange(arr.GetRange(start, k));
        return result;
    }
  
    static void Main()
    {
        // Input array, value, and k
        List<int> arr = new List<int> { -10, -50, 20, 17, 80 };
        int k = 2;
        int x = 20;
  
        // Call the function to find K closest elements
        List<int> result = Kclosest(arr, x, k);
  
        // Output the result list
        Console.Write("[");
        for (int i = 0; i < result.Count; i++)
        {
            Console.Write(result[i]);
            if (i < result.Count - 1)
            {
                Console.Write(",");
            }
        }
        Console.Write("]");
    }
}


Javascript




function GFG(arr, x, k) {
    // Sort the array
    arr.sort((a, b) => a - b);
    // if x is less than the first element
    if (x < arr[0]) {
        return arr.slice(0, k);
    }
    // if x is greater than the last element
    else if (x > arr[arr.length - 1]) {
        return arr.slice(arr.length - k);
    }
    // Apply sliding window on the auxiliary array
    else {
        const aux = arr.map(ele => Math.abs(ele - x));
        let i = 0;
        let j = 0;
        let s = 0;
        let miniS = Infinity;
        // Find the window with the smallest sum
        while (j < aux.length) {
            s += aux[j];
            if (j - i + 1 < k) {
                j++;
            } else if (j - i + 1 === k) {
                if (s < miniS) {
                    miniS = s;
                    start = i;
                    end = j;
                }
                s -= aux[i];
                i++;
                j++;
            }
        }
        // Return the first window with the smallest sum
        return arr.slice(start, end + 1);
    }
}
const arr = [-10, -50, 20, 17, 80];
const k = 2;
const x = 20;
console.log(GFG(arr, x, k));


Output

[17, 20]

Time Complexity: O(nlogn + n) = O(nlogn) , nlogn to sort and n for sliding window
Auxiliary Space: O(n), auxiliary space n taken



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads