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:
Implementation:
// 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 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 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# 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 |
<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> |
Output
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
So, the time complexity of the algorithm is
So the Overall time complexity would be