最小的自由数——分而治之算法

The smallest free number - divide and conquer algorithm

我正在读一本书 Pearls of Functional Algorithm Design。尝试为 最小的自由数字 问题实施分而治之的解决方案。

minfree xs = minfrom 0 (length xs) xs

minfrom a 0 _  = a
minfrom a n xs = if m == b - a
                    then minfrom b (n-m) vs
                    else minfrom a (m)   us
    where b = a + 1 + (n `div` 2)
          (us,vs) = partition (<b) xs
          m = length us

但是这个解决方案的工作速度并不比可能称为 "naive" 解决方案的解决方案快。这是

import Data.List ((\))
minfree' = head . (\) [0..]

不知道为什么会这样,分治算法有什么问题,如何改进。

尝试使用 BangPatterns,实现 partition 的版本,该版本还 returns 元组中第一个列表的长度,因此它消除了 m =length us 的额外遍历。 None 其中有改进。

第一个需要超过 5 秒,而第二个在 ghci 中几乎立即完成输入 [0..9999999].

您有病理输入,head . (\) [0..] 在 O(N) 时间内执行。 \ 定义为 follows:

(\) =  foldl (flip delete)

delete x xs 是一个 O(N) 操作,它从 xs 中删除第一个 xfoldl (flip delete) xs ysys 的所有元素从 xs 中一一删除。

[0..] \ [0..9999999]中,我们总是在列表的头部找到下一个要删除的元素,所以结果可以在线性时间内评估。

如果您改为在 GHCi 中键入 minfree' (reverse [0..9999999]),这将花费二次方时间,并且您会发现它几乎永远不会完成。

另一方面,分而治之算法不会减慢反向输入的速度。