通常,您不希望使用循环来实现F#中的复杂迭代/递归函数。这就是尾递归函数的优点。
为了得到低于O(n2)的计算复杂度,怎么样:考虑一组候选加数,它是最初的一组完整数字。现在看看这个集合中最大和最小数字的总和。如果该总和大于目标号码,则最大号码不会与任何事物的目标号码相加。反过来也是如此。
继续从候选组中删除最小或最大的数字,直到该组为空或已找到匹配。
的代码看起来是这样的:
let rec f M x =
if Set.isEmpty M then false else
let biggest, smallest = Set.maxElement M, Set.minElement M
let sum = biggest + smallest
if sum > x then f (Set.remove biggest M) x
elif sum < x then f (Set.remove smallest M) x
elif sum = x then true
else failwith "Encountered failure to compare numbers/NaN"
当我看的数学定义,它似乎并不为目标数是集合的要求。但是,如果这个问题,只是事先检查:
let fChecked M x =
if Set.contains x M then f M x
else invalidArg "x" "Target number is not contained in set."
汤姆使这个通用在可比的类型,功能可以被标记inline
。
设置的操作是O(log n),我们遍历整个事情,乘以O(n),使得总复杂度为O(n log n)(其中n是集合中元素的数量)。
有效极速版
如果它是关于实际速度,而不是“只是”计算复杂,数组可能更快,比一成不变套。下面是一个使用数组索引版本:
/// Version where M is types as an unsorted array we're allowed to sort
let f M x =
Array.sortInPlace M
let rec iter iLow iHigh =
if iLow > iHigh then false else
let sum = M.[iLow] + M.[iHigh]
if sum > x then iter iLow (iHigh - 1)
elif sum < x then iter (iLow + 1) iHigh
elif sum = x then true
else failwith "Encountered failure to compare numbers/NaN"
iter 0 (M.Length - 1)
需要注意的是,我们可以在数组,如果同组中重复使用预先排序,使这项工作的复杂每次调用同一组下降到为O(n)。
这是偶然的作业吗?当有人问大O的限制算法时,我只需要问。 O(n2)对于这个问题是显而易见的。 –
@GuyCoder:嗯,这是一个任务,可以在后面的考试中提出,我正在尝试写在F#中;)谢谢你的第二个评论,主席先生 - 我意识到我忘记了一个'不' – Unknown6656
在这种情况下,使用Seq.find而不是循环 –