我有一个固定的常数整数值数组,大约有300个项目(A组)。该算法的目标是从该数组中选择两个数字(X和Y),这些数字符合基于输入 R 的多个标准。
正式要求:
从集合 A 中选择值 X 和 Y ,使表达式 X * Y /(X + Y)为尽可能接近 R 。
这就是它的全部。我需要一个简单的算法来做到这一点。
其他信息:
Set A可以以任何方式进行排序或存储,最终将进行硬编码。此外,通过一些数学计算,可以证明给定 X 的最佳 Y 是Set A 中最接近的值表达式 X * R /(XR)。此外, X 和 Y 将始终大于 R
由此,我得到了一个简单的迭代算法,可以正常工作:
int minX = 100000000;
int minY = 100000000;
foreach X in A
if(X<=R)
continue;
else
Y=X*R/(X-R)
Y=FindNearestIn(A, Y);//do search to find closest useable Y value in A
if( X*Y/(X+Y) < minX*minY/(minX+minY) )
then
minX = X;
minY = Y;
end
end
end
我正在寻找比这种蛮力方法更优雅的方法。建议?
答案 0 :(得分:7)
对于可能“更优雅”的解决方案,请参阅解决方案2.
解决方案1)
为什么不创建R的所有可能的300 * 300/2或(300 * 299/2)个可能的精确值,将它们排序为数组B说,然后给出一个R,使用二分搜索在B中找到与R最接近的值,然后选择相应的X和Y.
我认为拥有数组B(带有X&amp; Y信息)不会是一个很大的内存占用,并且很容易被硬编码(使用代码编写代码!: - ))。
这将相当快:最坏情况~17次比较。
解决方案2)
您也可以执行以下操作(未尝试证明,但似乎正确):
维护一个1 / X值的数组,已排序。
现在给出一个R,你试着在1 / X数组中用两个数字找到最接近1 / R的和。
为此你保持两个指向1 / X数组的指针,一个指向最小值,一个指向最大值,并保持递增1并递减另一个以找到最接近1 / R的指针。 (这是一个经典的访谈问题:查找排序数组是否有两个数字总和为X)
在最坏的情况下,这将是O(n)比较和添加。这也容易出现精确问题。但是,您可以通过维护反向排序的X数组来避免一些精度问题。
答案 1 :(得分:1)
我想到了两个想法:
1)由于集合A是常数,因此一些预处理可能会有所帮助。假设A的值跨度不是太大,您可以创建一个大小为N = max(A)的数组。对于每个索引i,您可以将最接近的值存储在A到i中。这样,您可以通过在恒定时间内找到最接近的值来改进算法,而不是使用二进制搜索。
2)我看到你省略了X&lt; = R,这是正确的。如果您定义X <= Y,则可以进一步限制搜索范围,因为X> 2R也不会产生任何解决方案。因此,要扫描的范围是R&lt; X&lt; = 2R,这保证没有对称解,并且X <= Y。
答案 2 :(得分:0)
当输入的大小(大致)恒定时,O(n * log(n))解决方案可能比特定的O(n)解决方案运行得更快。
我会从您理解最佳的解决方案开始,并在需要时从那里进行优化。