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) 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 k-th 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 which 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.
 

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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;
}
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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 
            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
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

# 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 
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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 - 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)
  {
    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
chevron_right

Output: 
 



1


The time complexity of the algorithm is O( n*logn + n*logn*logn). Sorting takes O(n*logn). After that the main binary search over low and high takes O(n*logn*logn) time because each call to the function int f(int c, int n, int* a) takes time O(n*logn).

This article is contributed by Hemang Sarkar. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
 

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




Recommended Posts:


Article Tags :
Practice Tags :