【发布时间】:2011-03-30 09:38:12
【问题描述】:
假设我有一个排序的整数数组int[],我想搜索最接近某个输入数字的较小值。
例如,如果数组包含 (1) , (23), (57) , (59), (120) 并且输入为 109,则输出应为 59。
我只是想看看建议并与我已有的方法进行比较。
【问题讨论】:
假设我有一个排序的整数数组int[],我想搜索最接近某个输入数字的较小值。
例如,如果数组包含 (1) , (23), (57) , (59), (120) 并且输入为 109,则输出应为 59。
我只是想看看建议并与我已有的方法进行比较。
【问题讨论】:
使用Array.BinarySearch。如果输入在列表中,它将返回索引,如果不是,则返回第一个较大值的索引的补码。您只需反转结果并减去一个以获得最接近的较小值的索引。
int[] arr = { 1, 23, 57, 59, 120 };
int index = Array.BinarySearch(arr, 109);
if (index < 0)
{
index = ~index - 1;
}
if (index >= 0)
{
var result = arr[index];
}
请注意,如果您的输入小于最小元素,则您没有明确定义的答案。
【讨论】:
~index 将是 0,因为 1 是次高的数字,所以 ~index - 1 将是 -1。没有比输入小的元素,所以没有有效的答案。
使用 Linq:
int[] arr = new[] { 1, 23, 57, 59, 120 };
int target = 109;
int max = arr.Where(n => n < target).Max();
也许不是最快的,但可能是最容易实现的。也不像二分搜索那样依赖被排序的数组。
请注意,如果Where 过滤器没有生成任何元素,则对Max 的调用将引发异常,因此您可能需要检查是否有可能。
【讨论】:
我会选择 linq 解决方案(更新:添加更多代码以防止与恐惧的类似解决方案相似):
int[] arr1 = { 1, 23, 57, 59, 120 };
int maxResult;
string errorMsg;
try
{
maxResult = arr1.Where(x => x <= 109).Max();
}
catch(Exception e)
{
errorMsg = e.Message;
// do some error stuff here :)
return null;
}
// party on your maxResult...
【讨论】:
int getIndex( long[] list, long value )
{
int top = 0;
int bot = list.length-1;
int mid=0;
while ( top <= bot )
{
mid = (top+bot)/2; // NB integer arithmetic
if ( value < list[mid] )
{
if ( mid == 0 )
// value < than first item
return -1;
else
bot = mid-1;
}
else // value >= list[mid]
{
if ( mid == list.length-1 )
// value is >= last item
break;
else if ( value >= list[mid+1] )
top = mid+1;
else // list[mid] must be biggest <= value
break;
}
}
return mid;
}
【讨论】:
只是为了推断其他 LINQ 解决方案,如果没有对象适合过滤器并期望列表都是正整数,则此扩展方法将返回 -1
public static int SearchForLimit(this IEnuemerable<int> sequence, Predicate<int> filter)
{
return (from i in sequence
let n = filter(i) ? i : -1
select n).Max()
}
用法如下所示:
int[] arr1 = { 1, 23, 57, 59, 120 };
int limitedBy109 = arr1.SearchForLimit(i => i < 109);
【讨论】: