【问题标题】:Haskell Memoization Codewars Number of trailing zeros of factorial nHaskell Memoization Codewars 阶乘 n 的尾随零数
【发布时间】:2016-10-17 02:12:01
【问题描述】:

我正在尝试解决名为:N 的尾随零数的 Codewars 问题!与哈斯克尔。 我知道我不需要计算阶乘来知道尾随零,实际上我只是在计算有多少个数字可以被 5 整除,以及每个数字有多少次。 我写了 2 个版本,一个在分解数字时使用 memoization 以获得可被 5 整除的次数,另一个不使用 memoization。 令我惊讶的是,假定的 DP 方法比普通的递归方法花费的时间更长。我可能在我的代码中做了一些非常愚蠢的事情。

这些是函数:

zeros x = helperZeros [1..x]
helperZeros :: [Integer] -> Integer
helperZeros  = sumArrayTuple . filter (\x -> x `mod` 5 == 0)
sumArrayTuple = foldl (\acc x -> acc + (fastDef x)) 0
data Tree a = Tree (Tree a) a (Tree a)
instance Functor Tree where
  fmap f (Tree l m r) = Tree (fmap f l) (f m) (fmap f r)
index :: Tree Integer -> Integer -> Integer
index (Tree _ m _) 0 = m
index (Tree l _ r) n = case (n-1) `divMod` 2 of
  (q,0) -> index l q
  (q,1) -> index r q
nats = go 0 1
  where
    go n s = Tree (go l s') n (go r s' )
      where
        l = n + s
        r = l + s
        s' = s * 2
fastDef:: Integer -> Integer
fastDef x = trace (show x) index memTreetDef x
memTreetDef = fmap (defact fastDef) nats
defact f n
  | n `mod` 5 /= 0 = 0
  | otherwise =  1 + f (n `div` 5)



zeros' x = helperZeros' [1..x]
helperZeros' :: [Integer] -> Integer
helperZeros'  = sumArrayTuple' . filter (\x -> x `mod` 5 == 0)
sumArrayTuple' = foldl (\acc x -> acc + (def x)) 0
def n
  | n `mod` 5 /= 0 = 0
  | otherwise = 1 + def (n `div` 5)

我要记住的是 defact 函数的结果,例如如果我已经计算了 defact 200,那么它将重用这个结果来计算 defact 1000。

我对 Haskell 中的 DP 相当陌生。

【问题讨论】:

  • 你不也需要计算二的数量吗?
  • @Bergi 你总是有足够的二来匹配所有的五!

标签: haskell dynamic-programming factorial


【解决方案1】:

如果您在此处使用trace 和show 测试您的代码性能,那就是问题所在:与主代码相比,它们非常慢。如果不是,则变体的性能必须大致相同。

def 函数不适合记忆。递归的平均深度与1 差别不大。其余的复杂度被降低到操作mod,也就是几乎不比查表成本高的除法(并且被常数除法可以优化为乘法)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-06
    • 1970-01-01
    • 2017-10-10
    • 2022-11-10
    • 1970-01-01
    • 2012-06-06
    相关资源
    最近更新 更多