k-th smallest absolute difference of two elements in an array
We are given an array of size n containing positive integers. The absolute difference between values at indices i and j is |a[i] – a[j]|. There are n*(n-1)/2 such pairs and we are asked to print the kth (1 <= k <= n*(n-1)/2) as the smallest absolute difference among all these pairs.
Examples:
Input : a[] = {1, 2, 3, 4} k = 3 Output : 1 The possible absolute differences are : {1, 2, 3, 1, 2, 1}. The 3rd smallest value among these is 1.
Input : n = 2 a[] = {10, 10} k = 1 Output : 0
Naive Method is to find all the n*(n-1)/2 possible absolute differences in O(n^2) and store them in an array. Then sort this array and print the kth minimum value from this array. This will take time O(n^2 + n^2 * log(n^2)) = O(n^2 + 2*n^2*log(n)).
The naive method won’t be efficient for large values of n, say n = 10^5.
An Efficient Solution is based on Binary Search.
1) Sort the given array a[]. 2) We can easily find the least possible absolute difference in O(n) after sorting. The largest possible difference will be a[n-1] - a[0] after sorting the array. Let low = minimum_difference and high = maximum_difference. 3) while low < high: 4) mid = (low + high)/2 5) if ((number of pairs with absolute difference <= mid) < k): 6) low = mid + 1 7) else: 8) high = mid 9) return low
We need a function that will tell us the number of pairs with a difference <= mid efficiently. Since our array is sorted, this part can be done like this:
1) result = 0 2) for i = 0 to n-1: 3) result = result + (upper_bound(a+i, a+n, a[i] + mid) - (a+i+1)) 4) return result
Here upper_bound is a variant of binary search that returns a pointer to the first element from a[i] to a[n-1] which is greater than a[i] + mid. Let the pointer returned be j. Then a[i] + mid < a[j]. Thus, subtracting (a+i+1) from this will give us the number of values whose difference with a[i] is <= mid. We sum this up for all indices from 0 to n-1 and get the answer for the current mid.
Flowchart is as follows:

Flowchart
Implementation:
C++
// C++ program to find k-th absolute difference // between two elements #include<bits/stdc++.h> using namespace std; // returns number of pairs with absolute difference // less than or equal to mid. int countPairs( int *a, int n, int mid) { int res = 0; for ( int i = 0; i < n; ++i) // Upper bound returns pointer to position // of next higher number than a[i]+mid in // a[i..n-1]. We subtract (a + i + 1) from // this position to count res += upper_bound(a+i, a+n, a[i] + mid) - (a + i + 1); return res; } // Returns k-th absolute difference int kthDiff( int a[], int n, int k) { // Sort array sort(a, a+n); // Minimum absolute difference int low = a[1] - a[0]; for ( int i = 1; i <= n-2; ++i) low = min(low, a[i+1] - a[i]); // Maximum absolute difference int high = a[n-1] - a[0]; // Do binary search for k-th absolute difference while (low < high) { int mid = (low+high)>>1; if (countPairs(a, n, mid) < k) low = mid + 1; else high = mid; } return low; } // Driver code int main() { int k = 3; int a[] = {1, 2, 3, 4}; int n = sizeof (a)/ sizeof (a[0]); cout << kthDiff(a, n, k); return 0; } |
Java
// Java program to find k-th absolute difference // between two elements import java.util.Scanner; import java.util.Arrays; class GFG { // returns number of pairs with absolute // difference less than or equal to mid static int countPairs( int [] a, int n, int mid) { int res = 0 , value; for ( int i = 0 ; i < n; i++) { // Upper bound returns pointer to position // of next higher number than a[i]+mid in // a[i..n-1]. We subtract (ub + i + 1) from // this position to count if (a[i]+mid>a[n- 1 ]) res+=(n-(i+ 1 )); else { int ub = upperbound(a, n, a[i]+mid); res += (ub- (i+ 1 )); } } return res; } // returns the upper bound static int upperbound( int a[], int n, int value) { int low = 0 ; int high = n; while (low < high) { final int mid = (low + high)/ 2 ; if (value >= a[mid]) low = mid + 1 ; else high = mid; } return low; } // Returns k-th absolute difference static int kthDiff( int a[], int n, int k) { // Sort array Arrays.sort(a); // Minimum absolute difference int low = a[ 1 ] - a[ 0 ]; for ( int i = 1 ; i <= n- 2 ; ++i) low = Math.min(low, a[i+ 1 ] - a[i]); // Maximum absolute difference int high = a[n- 1 ] - a[ 0 ]; // Do binary search for k-th absolute difference while (low < high) { int mid = (low + high) >> 1 ; if (countPairs(a, n, mid) < k) low = mid + 1 ; else high = mid; } return low; } // Driver function to check the above functions public static void main(String args[]) { Scanner s = new Scanner(System.in); int k = 3 ; int a[] = { 1 , 2 , 3 , 4 }; int n = a.length; System.out.println(kthDiff(a, n, k)); } } // This code is contributed by nishkarsh146 |
Python3
# Python3 program to find # k-th absolute difference # between two elements from bisect import bisect as upper_bound # returns number of pairs with # absolute difference less than # or equal to mid. def countPairs(a, n, mid): res = 0 for i in range (n): # Upper bound returns pointer to position # of next higher number than a[i]+mid in # a[i..n-1]. We subtract (a + i + 1) from # this position to count res + = upper_bound(a, a[i] + mid) return res # Returns k-th absolute difference def kthDiff(a, n, k): # Sort array a = sorted (a) # Minimum absolute difference low = a[ 1 ] - a[ 0 ] for i in range ( 1 , n - 1 ): low = min (low, a[i + 1 ] - a[i]) # Maximum absolute difference high = a[n - 1 ] - a[ 0 ] # Do binary search for k-th absolute difference while (low < high): mid = (low + high) >> 1 if (countPairs(a, n, mid) < k): low = mid + 1 else : high = mid return low # Driver code k = 3 a = [ 1 , 2 , 3 , 4 ] n = len (a) print (kthDiff(a, n, k)) # This code is contributed by Mohit Kumar |
C#
// C# program to find k-th // absolute difference // between two elements using System; class GFG{ // returns number of pairs // with absolute difference // less than or equal to mid static int countPairs( int [] a, int n, int mid) { int res = 0; for ( int i = 0; i < n; i++) { // Upper bound returns pointer // to position of next higher // number than a[i]+mid in // a[i..n-1]. We subtract // (ub + i + 1) from // this position to count int ub = upperbound(a, n, a[i] + mid); res += (ub - (i)); } return res; } // returns the upper bound static int upperbound( int []a, int n, int value) { int low = 0; int high = n; while (low < high) { int mid = (low + high)/2; if (value >= a[mid]) low = mid + 1; else high = mid; } return low; } // Returns k-th absolute // difference static int kthDiff( int []a, int n, int k) { // Sort array Array.Sort(a); // Minimum absolute // difference int low = a[1] - a[0]; for ( int i = 1; i <= n - 2; ++i) low = Math.Min(low, a[i + 1] - a[i]); // Maximum absolute // difference int high = a[n - 1] - a[0]; // Do binary search for // k-th absolute difference while (low < high) { int mid = (low + high) >> 1; if (countPairs(a, n, mid) < k) low = mid + 1; else high = mid; } return low; } // Driver code public static void Main(String []args) { int k = 3; int []a = {1, 2, 3, 4}; int n = a.Length; Console.WriteLine(kthDiff(a, n, k)); } } // This code is contributed by gauravrajput1 |
Javascript
<script> // JavaScript program to find k-th // absolute difference // between two elements // returns number of pairs // with absolute difference // less than or equal to mid function countPairs(a, n, mid) { let res = 0; for (let i = 0; i < n; i++) { // Upper bound returns pointer // to position of next higher // number than a[i]+mid in // a[i..n-1]. We subtract // (ub + i + 1) from // this position to count let ub = upperbound(a, n, a[i] + mid); res += (ub - (i)); } return res; } // returns the upper bound function upperbound(a, n, value) { let low = 0; let high = n; while (low < high) { let mid = (low + high) / 2; if (value >= a[mid]) low = mid + 1; else high = mid; } return low; } // Returns k-th absolute // difference function kthDiff(a, n, k) { // Sort array a.sort((a, b) => a - b); // Minimum absolute // difference let low = a[1] - a[0]; for (let i = 1; i <= n - 2; ++i) low = Math.min(low, a[i + 1] - a[i]); // Maximum absolute // difference let high = a[n - 1] - a[0]; // Do binary search for // k-th absolute difference while (low < high) { let mid = (low + high) >> 1; if (countPairs(a, n, mid) < k) low = mid + 1; else high = mid; } return low; } // Driver code let k = 3; let a = [1, 2, 3, 4]; let n = a.length; document.write(kthDiff(a, n, k)); // This code is contributed by gfgking </script> |
1
Time Complexity: O(nlogn)
Auxiliary Space: O(1)
Suppose, the maximum element in the array is, and the minimum element is a minimum element in the array is . Then time taken for the binary_search will be , and the time taken for the upper_bound function will be
So, the time complexity of the algorithm is . Sorting takes
. After that the main binary search over low and high takes
time because each call to the function countPairs takes time
.
So the Overall time complexity would be
This article is contributed by Hemang Sarkar. If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please Login to comment...