Find K closest elements to given Value in Unsorted Array
Last Updated :
30 Apr, 2024
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
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++
#include <bits/stdc++.h>
using namespace std;
void printKclosest( int arr[], int n, int x,
int k)
{
priority_queue<pair< int , int > > pq;
for ( int i = 0; i < k; i++)
pq.push({ abs (arr[i] - x), i });
for ( int i = k; i < n; i++) {
int diff = abs (arr[i] - x);
if (diff > pq.top().first)
continue ;
pq.pop();
pq.push({ diff, i });
}
while (pq.empty() == false ) {
cout << arr[pq.top().second] << " " ;
pq.pop();
}
}
int main()
{
int arr[] = { -10, -50, 20, 17, 80 };
int X = 20, K = 2;
int N = sizeof (arr) / sizeof (arr[0]);
printKclosest(arr, N, X, K);
return 0;
}
|
Java
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)
{
PriorityQueue<Pair> pq
= new PriorityQueue<>( new Comparator<Pair>() {
public int compare(Pair p1, Pair p2)
{
return p2.getValue().compareTo(
p1.getValue());
}
});
for ( int i = 0 ; i < k; i++) {
pq.offer(
new Pair(arr[i], Math.abs(arr[i] - x)));
}
for ( int i = k; i < n; i++) {
int diff = Math.abs(arr[i] - x);
if (diff > pq.peek().getValue())
continue ;
pq.poll();
pq.offer( new Pair(arr[i], diff));
}
while (!pq.isEmpty()) {
System.out.print(pq.poll().getKey() + " " );
}
}
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);
}
}
|
Python3
import math
import sys
from queue import PriorityQueue
def printKclosest(arr,n,x,k):
pq = PriorityQueue()
for i in range (k):
pq.put(( - abs (arr[i] - x),i))
for i in range (k,n):
diff = abs (arr[i] - x)
p,pi = pq.get()
curr = - p
if diff>curr:
pq.put(( - curr,pi))
continue
else :
pq.put(( - diff,i))
while ( not pq.empty()):
p,q = pq.get()
print ( "{} " . format (arr[q]),end = "")
if __name__ = = '__main__' :
arr = [ - 10 , - 50 , 20 , 17 , 80 ]
X, K = 20 , 2
N = len (arr)
printKclosest(arr, N, X, K)
|
C#
using System;
using System.Collections.Generic;
class GFG {
static void printKclosest( int [] arr, int n, int x,
int k)
{
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();
for ( int i = k; i < n; i++) {
int diff = Math.Abs(arr[i] - x);
if (diff > pq[0].Item1)
continue ;
pq.RemoveAt(0);
pq.Add( new Tuple< int , int >(diff, i));
pq.Sort();
pq.Reverse();
}
while (pq.Count > 0) {
Console.Write(arr[pq[0].Item2] + " " );
pq.RemoveAt(0);
}
}
static void Main()
{
int [] arr = { -10, -50, 20, 17, 80 };
int X = 20, K = 2;
int N = arr.Length;
printKclosest(arr, N, X, K);
}
}
|
Javascript
function printKclosest(arr, x, k) {
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]);
for (let i = k; i < arr.length; i++) {
const diff = Math.abs(arr[i] - x);
if (diff > pq[0][0]) {
continue ;
}
pq.shift();
pq.push([diff, i]);
pq.sort((a, b) => b[0] - a[0]);
}
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);
|
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(arr.begin(), arr.end());
vector< int > result;
if (x < arr[0]) {
result.assign(arr.begin(), arr.begin() + k);
return result;
}
if (x > arr[arr.size() - 1]) {
result.assign(arr.end() - k, arr.end());
return result;
}
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;
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++;
}
}
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;
}
|
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) {
arr.sort( null );
List<Integer> result = new ArrayList<>();
if (x < arr.get( 0 )) {
result.addAll(arr.subList( 0 , k));
return result;
}
if (x > arr.get(arr.size() - 1 )) {
result.addAll(arr.subList(arr.size() - k, arr.size()));
return result;
}
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 ;
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++;
}
}
result.addAll(arr.subList(start, end + 1 ));
return result;
}
public static void main(String[] args) {
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);
System.out.print( "[" );
for ( int ele : result) {
System.out.print(ele + "," );
}
System.out.print( "]" );
}
}
|
Python
import math
def Kclosest(arr, x, k):
arr.sort()
if x < arr[ 0 ]:
arr = arr[:k]
return arr
elif x > arr[ - 1 ]:
arr = arr[ len (arr) - k:]
return arr
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" )
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
arr = arr[start:end + 1 ]
return arr
arr = [ - 10 , - 50 , 20 , 17 , 80 ]
k = 2
x = 20
print (Kclosest(arr, x, k))
|
C#
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static List< int > Kclosest(List< int > arr, int x, int k)
{
arr.Sort();
List< int > result = new List< int >();
if (x < arr[0])
{
result.AddRange(arr.Take(k));
return result;
}
if (x > arr[arr.Count - 1])
{
result.AddRange(arr.Skip(arr.Count - k));
return result;
}
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;
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++;
}
}
result.AddRange(arr.GetRange(start, k));
return result;
}
static void Main()
{
List< int > arr = new List< int > { -10, -50, 20, 17, 80 };
int k = 2;
int x = 20;
List< int > result = Kclosest(arr, x, k);
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) {
arr.sort((a, b) => a - b);
if (x < arr[0]) {
return arr.slice(0, k);
}
else if (x > arr[arr.length - 1]) {
return arr.slice(arr.length - k);
}
else {
const aux = arr.map(ele => Math.abs(ele - x));
let i = 0;
let j = 0;
let s = 0;
let miniS = Infinity;
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 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
Share your thoughts in the comments
Please Login to comment...