【问题标题】:Hamming numbers in HaskellHaskell中的汉明数
【发布时间】:2013-03-13 11:12:38
【问题描述】:

我需要定义仅素因数为 2、3 和 5 的数字列表,即汉明数。 (即2^i * 3^j * 5^k形式的数字。序列以1、2、3、4、5、6、8、9、10、12、15、...开头)

我可以使用factors 函数或其他方式来实现。下面的factors 应该返回其参数的因子。我相信我已经正确地实现了它。

   factors :: Int -> [Int]
   factors n = [x | x <- [1..(div n 2) ++ n], mod n x == 0]

我尝试使用列表推导来制作 2^i * 3^j * 5^k 的列表,但在编写守卫时遇到了困难:

hamming :: [Int]
hamming = [n | n <- [1..], „where n is a member of helper“]

helper :: [Int]
helper = [2^i * 3^j * 5^k | i <- [0..], j <- [0..], k <- [0..]]

【问题讨论】:

  • 顺便说一句,factors 函数有语法错误。通过尽可能小的更改,可以将其固定为factors n = [x | x &lt;- [1..(div n 2)] ++ [n], mod n x == 0]

标签: haskell factors hamming-numbers


【解决方案1】:

我可以使用factors 函数或其他方式来实现。

我建议不这样做。

一个简单的方法是实现一个函数,得到一个数的素数分解,然后你可以有

isHamming :: Integer -> Bool
isHamming n = all (< 7) $ primeFactors n

然后将用于过滤所有正整数的列表:

hammingNumbers :: [Integer]
hammingNumbers = filter isHamming [1 .. ]

另一种更有效的方法是避免除法和过滤,并创建一个仅包含汉明数的列表。

一种简单的方法是使用数字n 是汉明数当且仅当

  • n == 1,或
  • n == 2*k,其中k 是汉明数,或
  • n == 3*k,其中k 是汉明数,或
  • n == 5*k,其中k 是一个汉明数。

然后你可以创建所有汉明数的列表

hammingNumbers :: [Integer]
hammingNumbers = 1 : mergeUnique (map (2*) hammingNumbers)
                                 (mergeUnique (map (3*) hammingNumbers)
                                              (map (5*) hammingNumbers))

mergeUnique 将两个排序列表合并在一起,删除重复项。

这已经相当有效了,但是it can be improved by avoiding producing duplicates from the beginning

【讨论】:

  • 其实这个hammingNumbers等价于[2^i*3^j*5^k | k&lt;-[0..], j&lt;-[0..], i&lt;-[0..]]。理论上,它包含所有汉明数,但实际上它只是[1,2,4,8,16,32,...]
  • 那么我们怎样才能让它创建所有的汉明数呢?
  • @johnstamos 给它无限的时间 ;-) 你可以得到它们[2^i * 3^j * 5^k | n &lt;- [0 .. ], k &lt;- [0 .. n], let m = n-k, j &lt;- [0 .. m], let i = m-j]。但如果你想让它们按升序排列,我提出的合并策略是我所知道的最好的方式。
  • 非常感谢丹尼尔。不过,我对您的代码有几个问题。在 isHamming 中,“all (
  • all 是一个函数,它接受一个谓词和一个列表,并检查所有列表元素是否满足谓词all :: (a -&gt; Bool) -&gt; [a] -&gt; Bool;对于素因数,(&lt; 7) 检查它们是2, 3 还是5(*) 只是乘法,(2*) 是运算符部分,所以 (2*) = \x -&gt; 2*x。函数primeFactorsunion 仍有待编写(或从其他地方复制)。我想这是一种练习,要让你从中学习,你至少必须自己做一部分。如果这不是一个练习,那就去从另一个问题中获取代码。
【解决方案2】:

注意hamming设置为

{2^i*3^j*5^k | (i, j, k) ∈ T}

在哪里

T = {(i, j, k) | i ∈ [0..], j ∈ [0..], k ∈ [0..]}

但是我们不能使用 [(i, j, k) | i (0, 0, k)。
给定任何(i,j,k)elem (i,j,k) T 应在有限时间内返回 True。
听起来很熟悉?您可以回忆一下您之前提出的问题: haskell infinite list of incrementing pairs

在那个问题中,哈马尔给出了配对的答案。我们可以将其推广到三元组。

triples = [(i,j,t-i-j)| t <- [0..], i <- [0..t], j <- [0..t-i]]
hamming = [2^i*3^j*5^k | (i,j,k) <- triples]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-21
    • 1970-01-01
    • 2011-12-26
    • 2018-04-04
    • 1970-01-01
    • 2014-09-23
    • 2020-07-03
    • 2017-09-10
    相关资源
    最近更新 更多