📌  相关文章
📜  数组中两个元素的第 k 个最小绝对差

📅  最后修改于: 2022-05-13 01:57:48.618000             🧑  作者: Mango

数组中两个元素的第 k 个最小绝对差

我们得到一个包含正整数的大小为 n 的数组。索引 i 和 j 处的值之间的绝对差为 |a[i] – a[j]|。有 n*(n-1)/2 个这样的对,我们被要求打印所有这些对中第 k 个 (1 <= k <= n*(n-1)/2) 的最小绝对差。
例子:

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

朴素的方法是在 O(n^2) 中找到所有 n*(n-1)/2 个可能的绝对差异并将它们存储在一个数组中。然后对该数组进行排序并打印该数组中的第 k 个最小值。这将花费时间 O(n^2 + n^2 * log(n^2)) = O(n^2 + 2*n^2*log(n))。
对于较大的 n 值,例如 n = 10^5,这种简单的方法不会有效。
一个有效的解决方案是基于二分搜索。

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

我们需要一个函数来有效地告诉我们差异 <= mid 的对数。
由于我们的数组是排序的,这部分可以这样完成:

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

这里的upper_bound 是二分查找的一种变体,它返回一个指向从a[i] 到a[n-1] 的第一个元素的指针,该指针大于a[i] + mid。令返回的指针为 j。然后 a[i] + mid < a[j]。因此,从中减去 (a+i+1) 将得到与 a[i] 之差 <= mid 的值的数量。我们对从 0 到 n-1 的所有索引进行总结,并得到当前中间值的答案。

C++
// C++ program to find k-th absolute difference
// between two elements
#include
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


输出:

1

假设,数组中的最大元素是max ,最小元素是数组中的最小元素是min .

然后 binary_search 花费的时间将是O(log(max-min)) ,upper_bound函数所用的时间为O(log(n)) .

因此,算法的时间复杂度为O( n*log(n) + log(max-min)*n*log(n)) .排序需要O(n*log(n)) .之后,对低和高的主要二分搜索需要O(log(max-min)*n*log(n)) 时间,因为对函数countPairs 的每次调用都需要时间O(n*log(n)) .

所以总时间复杂度是O(n*log(n)*log(max-min))

?list=PLqM7alHXFySEQDk2MDfbwEdjd2svVJH9p