给定一个已排序的数组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