我想知道如何使用memoization制作有效的算法。特别是,有没有办法在Haskell中为索引值设置O(1)访问时间?
这是the problem described in detail。这是我对递归算法的尝试:
denom :: (Int, Int) -> [Int] -> Int
denom (_, 0) _ = 0
denom (0, _) _ = (maxBound :: Int) - 1000 -- subtracting 1000 otherwise overflows
denom (i, j) di
| v > j = denom (i-1, j) di
| otherwise = min (denom (i-1, j) di) (1 + denom (i, j-v) di)
where v = di !! (i - 1)
另外,我如何在Haskell中声明INFINITY
以便min
在所有情况下都有效?
答案 0 :(得分:1)
首先,要在Haskell中进行O(1)
访问,标准的首选库是Data.Array。
第二,定义某种类型附近的东西的一般方法,但不知何故"外部"它是使用Maybe
类型;这是我为INFINITY
推荐的内容。另外,我认为这在算法中更有意义,因为INFINITY
实际上意味着"我们无法用这组面额来表达这个值#34;而不是"我们可以用无限数量的硬币制作这个值"。
因此,使用Maybe
,我们要定义的第一件事是min
的版本Maybe Int
:
myMin :: Ord a => Maybe a -> Maybe a -> Maybe a
myMin (Just a) (Just b) = Just $ min a b
myMin Nothing x = x
myMin x Nothing = x
然后,使用我们可以使用链接页面中给出的算法来解决此问题:
minCoinCoint :: Int -> [Int] -> Maybe Int
minCoinCoint target denoms = res (target, length denoms)
where
denomArray = listArray (0, length denoms) (0:denoms)
myArrayBounds = ((0, 0), (target, length denoms))
myArray = array myArrayBounds [(i, res i) | i <- range myArrayBounds]
res (_, 0) = Nothing
res (0, _) = Just 0
res (t, d) = let dval = denomArray ! d
prev1 = myArray ! (t, d-1)
prev2 = if t >= dval
then (+1) <$> (myArray ! (t-dval, d))
else Nothing
in myMin prev1 prev2
就是这样。 (好吧,假设你还记得文件顶部的import Data.Array
行)
请注意,myArray
是通过引用res
构建的,res
通过查找myArray
中的值来进行所有递归调用。
这种语法可能有点令人困惑:
(+1) <$> (myArray ! (t-dval, d))
这样做是因为记住myArray
的每个元素都不是Int
而是Maybe Int
。该语法说&#34;将函数(+1)
应用于值(myArray ! (t-dval, d))
&#34;的内部,以便Just 4
成为Just 5
,但是Nothing
将保持为Nothing
。