📜  查找k个最接近给定值的元素

📅  最后修改于: 2021-04-23 19:12:34             🧑  作者: Mango

给定一个已排序的数组arr []和一个值X,请在arr []中找到最接近X的k个元素。

例子:

Input: K = 4, X = 35
       arr[] = {12, 16, 22, 30, 35, 39, 42, 
               45, 48, 50, 53, 55, 56}
Output: 30 39 42 45

请注意,如果元素存在于数组中,则不应出现在输出中,仅需要其他最接近的元素。

在以下解决方案中,假定数组的所有元素都是不同的。
一个简单的解决方案是对k个最接近的元素进行线性搜索。
1)从第一个元素开始并搜索交叉点(元素小于或等于X且元素大于之后的点)。此步骤需要O(n)时间。
2)一旦找到交叉点,就可以比较交叉点两侧的元素以打印k个最接近的元素。此步骤需要O(k)时间。
上述解决方案的时间复杂度为O(n)。

一个优化的解决方案是在O(Logn + k)时间中找到k个元素。这个想法是使用二进制搜索来找到交叉点。一旦找到交叉点的索引,就可以在O(k)时间中打印k个最接近的元素。

C++
#include
 
/* Function to find the cross over point (the point before
which elements are smaller than or equal to x and after
which greater than x)*/
int findCrossOver(int arr[], int low, int high, int x)
{
// Base cases
if (arr[high] <= x) // x is greater than all
    return high;
if (arr[low] > x) // x is smaller than all
    return low;
 
// Find the middle point
int mid = (low + high)/2; /* low + (high - low)/2 */
 
/* If x is same as middle element, then return mid */
if (arr[mid] <= x && arr[mid+1] > x)
    return mid;
 
/* If x is greater than arr[mid], then either arr[mid + 1]
    is ceiling of x or ceiling lies in arr[mid+1...high] */
if(arr[mid] < x)
    return findCrossOver(arr, mid+1, high, x);
 
return findCrossOver(arr, low, mid - 1, x);
}
 
// This function prints k closest elements to x in arr[].
// n is the number of elements in arr[]
void printKclosest(int arr[], int x, int k, int n)
{
    // Find the crossover point
    int l = findCrossOver(arr, 0, n-1, x);
    int r = l+1; // Right index to search
    int count = 0; // To keep track of count of elements already printed
 
    // If x is present in arr[], then reduce left index
    // Assumption: all elements in arr[] are distinct
    if (arr[l] == x) l--;
 
    // Compare elements on left and right of crossover
    // point to find the k closest elements
    while (l >= 0 && r < n && count < k)
    {
        if (x - arr[l] < arr[r] - x)
            printf("%d ", arr[l--]);
        else
            printf("%d ", arr[r++]);
        count++;
    }
 
    // If there are no more elements on right side, then
    // print left elements
    while (count < k && l >= 0)
        printf("%d ", arr[l--]), count++;
 
    // If there are no more elements on left side, then
    // print right elements
    while (count < k && r < n)
        printf("%d ", arr[r++]), count++;
}
 
/* Driver program to check above functions */
int main()
{
int arr[] ={12, 16, 22, 30, 35, 39, 42,
            45, 48, 50, 53, 55, 56};
int n = sizeof(arr)/sizeof(arr[0]);
int x = 35, k = 4;
printKclosest(arr, x, 4, n);
return 0;
}


Java
// Java program to find k closest elements to a given value
class KClosest
{
    /* Function to find the cross over point (the point before
       which elements are smaller than or equal to x and after
       which greater than x)*/
    int findCrossOver(int arr[], int low, int high, int x)
    {
        // Base cases
        if (arr[high] <= x) // x is greater than all
            return high;
        if (arr[low] > x)  // x is smaller than all
            return low;
 
        // Find the middle point
        int mid = (low + high)/2;  /* low + (high - low)/2 */
 
        /* If x is same as middle element, then return mid */
        if (arr[mid] <= x && arr[mid+1] > x)
            return mid;
 
        /* If x is greater than arr[mid], then either arr[mid + 1]
          is ceiling of x or ceiling lies in arr[mid+1...high] */
        if(arr[mid] < x)
            return findCrossOver(arr, mid+1, high, x);
 
        return findCrossOver(arr, low, mid - 1, x);
    }
 
    // This function prints k closest elements to x in arr[].
    // n is the number of elements in arr[]
    void printKclosest(int arr[], int x, int k, int n)
    {
        // Find the crossover point
        int l = findCrossOver(arr, 0, n-1, x);
        int r = l+1;   // Right index to search
        int count = 0; // To keep track of count of elements
                       // already printed
 
        // If x is present in arr[], then reduce left index
        // Assumption: all elements in arr[] are distinct
        if (arr[l] == x) l--;
 
        // Compare elements on left and right of crossover
        // point to find the k closest elements
        while (l >= 0 && r < n && count < k)
        {
            if (x - arr[l] < arr[r] - x)
                System.out.print(arr[l--]+" ");
            else
                System.out.print(arr[r++]+" ");
            count++;
        }
 
        // If there are no more elements on right side, then
        // print left elements
        while (count < k && l >= 0)
        {
            System.out.print(arr[l--]+" ");
            count++;
        }
 
 
        // If there are no more elements on left side, then
        // print right elements
        while (count < k && r < n)
        {
            System.out.print(arr[r++]+" ");
            count++;
        }
    }
 
    /* Driver program to check above functions */
    public static void main(String args[])
    {
        KClosest ob = new KClosest();
        int arr[] = {12, 16, 22, 30, 35, 39, 42,
                     45, 48, 50, 53, 55, 56
                    };
        int n = arr.length;
        int x = 35, k = 4;
        ob.printKclosest(arr, x, 4, n);
    }
}
/* This code is contributed by Rajat Mishra */


Python3
# Function to find the cross over point
# (the point before which elements are
# smaller than or equal to x and after
# which greater than x)
def findCrossOver(arr, low, high, x) :
 
    # Base cases
    if (arr[high] <= x) : # x is greater than all
        return high
         
    if (arr[low] > x) : # x is smaller than all
        return low
     
    # Find the middle point
    mid = (low + high) // 2 # low + (high - low)// 2
     
    # If x is same as middle element,
    # then return mid
    if (arr[mid] <= x and arr[mid + 1] > x) :
        return mid
     
    # If x is greater than arr[mid], then
    # either arr[mid + 1] is ceiling of x
    # or ceiling lies in arr[mid+1...high]
    if(arr[mid] < x) :
        return findCrossOver(arr, mid + 1, high, x)
     
    return findCrossOver(arr, low, mid - 1, x)
 
# This function prints k closest elements to x
# in arr[]. n is the number of elements in arr[]
def printKclosest(arr, x, k, n) :
     
    # Find the crossover point
    l = findCrossOver(arr, 0, n - 1, x)
    r = l + 1 # Right index to search
    count = 0 # To keep track of count of
              # elements already printed
 
    # If x is present in arr[], then reduce
    # left index. Assumption: all elements
    # in arr[] are distinct
    if (arr[l] == x) :
        l -= 1
 
    # Compare elements on left and right of crossover
    # point to find the k closest elements
    while (l >= 0 and r < n and count < k) :
         
        if (x - arr[l] < arr[r] - x) :
            print(arr[l], end = " ")
            l -= 1
        else :
            print(arr[r], end = " ")
            r += 1
        count += 1
 
    # If there are no more elements on right
    # side, then print left elements
    while (count < k and l >= 0) :
        print(arr[l], end = " ")
        l -= 1
        count += 1
 
    # If there are no more elements on left
    # side, then print right elements
    while (count < k and r < n) :
        print(arr[r], end = " ")
        r += 1
        count += 1
 
# Driver Code
if __name__ == "__main__" :
 
    arr =[12, 16, 22, 30, 35, 39, 42,
              45, 48, 50, 53, 55, 56]
                 
    n = len(arr)
    x = 35
    k = 4
     
    printKclosest(arr, x, 4, n)
     
# This code is contributed by Ryuga


C#
// C# program to find k closest elements to
// a given value
using System;
 
class GFG {
     
    /* Function to find the cross over point
    (the point before which elements are
    smaller than or equal to x and after which
    greater than x)*/
    static int findCrossOver(int []arr, int low,
                                int high, int x)
    {
         
        // Base cases
        // x is greater than all
        if (arr[high] <= x)
            return high;
             
        // x is smaller than all
        if (arr[low] > x)
            return low;
 
        // Find the middle point
        /* low + (high - low)/2 */
        int mid = (low + high)/2;
 
        /* If x is same as middle element, then
        return mid */
        if (arr[mid] <= x && arr[mid+1] > x)
            return mid;
 
        /* If x is greater than arr[mid], then
        either arr[mid + 1] is ceiling of x or
        ceiling lies in arr[mid+1...high] */
        if(arr[mid] < x)
            return findCrossOver(arr, mid+1,
                                      high, x);
 
        return findCrossOver(arr, low, mid - 1, x);
    }
 
    // This function prints k closest elements
    // to x in arr[]. n is the number of
    // elements in arr[]
    static void printKclosest(int []arr, int x,
                                  int k, int n)
    {
         
        // Find the crossover point
        int l = findCrossOver(arr, 0, n-1, x);
         
        // Right index to search
        int r = l + 1;
         
        // To keep track of count of elements
        int count = 0;
 
        // If x is present in arr[], then reduce
        // left index Assumption: all elements in
        // arr[] are distinct
        if (arr[l] == x) l--;
 
        // Compare elements on left and right of
        // crossover point to find the k closest
        // elements
        while (l >= 0 && r < n && count < k)
        {
            if (x - arr[l] < arr[r] - x)
                Console.Write(arr[l--]+" ");
            else
                Console.Write(arr[r++]+" ");
            count++;
        }
 
        // If there are no more elements on right
        // side, then print left elements
        while (count < k && l >= 0)
        {
            Console.Write(arr[l--]+" ");
            count++;
        }
 
        // If there are no more elements on left
        // side, then print right elements
        while (count < k && r < n)
        {
            Console.Write(arr[r++] + " ");
            count++;
        }
    }
 
    /* Driver program to check above functions */
    public static void Main()
    {
        int []arr = {12, 16, 22, 30, 35, 39, 42,
                         45, 48, 50, 53, 55, 56};
        int n = arr.Length;
        int x = 35;
        printKclosest(arr, x, 4, n);
    }
}
 
// This code is contributed by nitin mittal.


PHP
 $x)
        return $low;
     
    // Find the middle point
    /* low + (high - low)/2 */
    $mid = ($low + $high)/2;
     
    /* If x is same as middle
       element, then return mid */
    if ($arr[$mid] <= $x and
        $arr[$mid + 1] > $x)
        return $mid;
     
    /* If x is greater than arr[mid],
       then either arr[mid + 1] is
       ceiling of x or ceiling lies
       in arr[mid+1...high] */
    if($arr[$mid] < $x)
        return findCrossOver($arr, $mid + 1,
                                 $high, $x);
     
    return findCrossOver($arr, $low,
                      $mid - 1, $x);
}
 
// This function prints k
// closest elements to x in arr[].
// n is the number of elements
// in arr[]
function printKclosest($arr, $x, $k, $n)
{
     
    // Find the crossover point
    $l = findCrossOver($arr, 0, $n - 1, $x);
     
    // Right index to search
    $r = $l + 1;
     
    // To keep track of count of
    // elements already printed
    $count = 0;
 
    // If x is present in arr[],
    // then reduce left index
    // Assumption: all elements
    // in arr[] are distinct
    if ($arr[$l] == $x) $l--;
 
    // Compare elements on left
    // and right of crossover
    // point to find the k
    // closest elements
    while ($l >= 0 and $r < $n
              and $count < $k)
    {
        if ($x - $arr[$l] < $arr[$r] - $x)
            echo $arr[$l--]," ";
        else
            echo $arr[$r++]," ";
        $count++;
    }
 
    // If there are no more
    // elements on right side,
    // then print left elements
    while ($count < $k and $l >= 0)
        echo $arr[$l--]," "; $count++;
 
    // If there are no more
    // elements on left side,
    // then print right elements
    while ($count < $k and $r < $n)
        echo $arr[$r++]; $count++;
}
 
// Driver Code
$arr =array(12, 16, 22, 30, 35, 39, 42,
                45, 48, 50, 53, 55, 56);
$n = count($arr);
$x = 35; $k = 4;
 
printKclosest($arr, $x, 4, $n);
 
// This code is contributed by anuj_67.
?>


Javascript


输出:

39 30 42 45