我有一个常数列表。我需要在数字列表中找到最接近x的数字。关于如何实现这个算法的任何想法?
答案 0 :(得分:8)
嗯,你不能比O(N)
更快地做到这一点,因为你必须检查所有数字,以确保你有最接近的数字。也就是说,为什么不使用一个简单的变量找到最小值,寻找与 x 具有最小绝对差值的变量?
如果你可以说列表是从头开始排序的(它允许随机访问,就像数组一样),那么更好的方法是使用二进制搜索。当您在索引 i 结束搜索时(没有找到 x ),只需选择该元素及其邻居中的最佳元素。
答案 1 :(得分:5)
我认为数组是无序的。按顺序,它可以更快
我认为最简单和最快的方法是使用线性算法来查找最小值或最大值,但不是比较值,而是比较它与针之间的差值的绝对值。
在C ++中(我不能用C#但它会类似)代码看起来像这样:
// array of numbers is haystack
// length is length of array
// needle is number which you are looking for ( or compare with )
int closest = haystack[0];
for ( int i = 0; i < length; ++i ) {
if ( abs( haystack[ i ] - needle ) < abs( closest - needle ) ) closest = haystack[i];
}
return closest;
答案 2 :(得分:3)
一般来说,本网站上的人不会为您做功课。由于您没有发布代码,我也不会发布代码。但是,这是一种可能的方法。
循环列表,从x中减去列表中的数字。取这个差值的绝对值,并将其与您获得的最佳结果进行比较,如果当前差异小于之前的最佳结果,请从列表中保存当前数字。在循环结束时,你会得到答案。
答案 3 :(得分:1)
private int? FindClosest(IEnumerable<int> numbers, int x)
{
return
(from number in numbers
let difference = Math.Abs(number - x)
orderby difference, Math.Abs(number), number descending
select (int?) number)
.FirstOrDefault();
}
Null表示没有最接近的号码。如果有两个具有相同差异的数字,它将选择最接近零的数字。如果两个数字的距离与零相同,则将选择正数。
编辑以回应Eric的评论:
这是一个具有相同语义但使用Min
运算符的版本。它需要IComparable<>
的实现,因此我们可以使用Min
,同时保留每个距离的数字。我还把它作为一种易于使用的扩展方法:
public static int? FindClosestTo(this IEnumerable<int> numbers, int targetNumber)
{
var minimumDistance = numbers
.Select(number => new NumberDistance(targetNumber, number))
.Min();
return minimumDistance == null ? (int?) null : minimumDistance.Number;
}
private class NumberDistance : IComparable<NumberDistance>
{
internal NumberDistance(int targetNumber, int number)
{
this.Number = number;
this.Distance = Math.Abs(targetNumber - number);
}
internal int Number { get; private set; }
internal int Distance { get; private set; }
public int CompareTo(NumberDistance other)
{
var comparison = this.Distance.CompareTo(other.Distance);
if(comparison == 0)
{
// When they have the same distance, pick the number closest to zero
comparison = Math.Abs(this.Number).CompareTo(Math.Abs(other.Number));
if(comparison == 0)
{
// When they are the same distance from zero, pick the positive number
comparison = this.Number.CompareTo(other.Number);
}
}
return comparison;
}
}
答案 4 :(得分:0)
可以使用SortedList完成:
Blog post on finding closest number
如果您正在寻找的复杂性只计算搜索的复杂性 O(log(n))。列表构建将花费 O(n * log(n))
如果您要将项目插入列表的次数比查询最接近的数字要多得多,那么最好的选择是使用List并使用朴素算法查询它最近的号码。每次搜索都将花费 O(n),但插入时间将缩短为 O(n)。
一般复杂性:如果集合中有 n 个数字且搜索 q 次 -
列表:O(n+q*n)
排序列表:O(n*log(n)+q*log(n))
意思是,从某些 q 排序列表将提供更好的复杂性。
答案 5 :(得分:0)
懒惰我没有检查过这个但是不应该这样做
private int FindClosest(IEnumerable<int> numbers, int x)
{
return
numbers.Aggregate((r,n) => Math.Abs(r-x) > Math.Abs(n-x) ? n
: Math.Abs(r-x) < Math.Abs(n-x) ? r
: r < x ? n : r);
}
答案 6 :(得分:0)
Haskell中:
import Data.List (minimumBy)
import Data.Ord (comparing)
findClosest :: (Num a, Ord a) => a -> [a] -> Maybe a
findClosest _ [] = Nothing
findClosest n xs = Just $ minimumBy (comparing $ abs . (+ n)) xs
答案 7 :(得分:0)
Performance wise custom code will be more use full.
List<int> results;
int targetNumber = 0;
int nearestValue=0;
if (results.Any(ab => ab == targetNumber ))
{
nearestValue= results.FirstOrDefault<int>(i => i == targetNumber );
}
else
{
int greaterThanTarget = 0;
int lessThanTarget = 0;
if (results.Any(ab => ab > targetNumber ))
{
greaterThanTarget = results.Where<int>(i => i > targetNumber ).Min();
}
if (results.Any(ab => ab < targetNumber ))
{
lessThanTarget = results.Where<int>(i => i < targetNumber ).Max();
}
if (lessThanTarget == 0 )
{
nearestValue= greaterThanTarget;
}
else if (greaterThanTarget == 0)
{
nearestValue= lessThanTarget;
}
else if (targetNumber - lessThanTarget < greaterThanTarget - targetNumber )
{
nearestValue= lessThanTarget;
}
else
{
nearestValue= greaterThanTarget;
}
}