【问题标题】:Check if number contains all digits检查数字是否包含所有数字
【发布时间】:2015-03-18 06:40:05
【问题描述】:

检查一个数字是否包含 Haskell 中的所有数字的有效方法是什么?修改列表效率极低,因此保留每个数字出现次数的列表是不行的。您可以在递归中保留 10 个 Bool 变量,在其中您可以遍历您的号码的数字列表,但这似乎太丑陋了。

【问题讨论】:

  • 你的意思是检查每个字符是否都是数字?或者是否所有可能的数字 0-9 至少出现一次?还是别的什么?

标签: haskell


【解决方案1】:

我的解决方案比user2407038's 快得多。

import Data.Bits
import Data.Char
import Data.List

hasAll10Digits = any (==1023) . scanl setBit (0::Int) . map digitToInt . show

ghci 中,它运行 hasAll10Digits (12^223451) 仅需 0.03 秒。

相比之下,user2407038 的代码运行时间约为 11 秒。

【讨论】:

  • 同样快速的实现是import qualified Data.Set as ShasAll10Digits = any ((== 10) . S.size) . scanl (flip S.insert) S.empty . show。它只是使用具有不同中间结构的相同算法来存储结果。这也适用于 Data.Map 在大约相同的时间内。
  • @bheklilr,是的,您可以这样做,但是可以合理地预期 No_signal 的解决方案运行得更快,只要列表正确融合(它们可能在 GHC 7.10 中但不会在GHC 7.8)。手动执行此操作似乎很合理,将anyscanl 换成更高阶的foldr。或者您可以手动删除show,无论如何这似乎可能会有所帮助。比较时请务必排除 RTS 启动时间。
  • @dfeuer,用 -O2 编译,它们也是相等的,map digitToInt . show 对于大数字来说比我能找到的任何东西都快
  • 什么 GHC 版本? scanl 在 7.10 之前对列表融合并不是很聪明......您是否尝试过 -fllvm 来加速手动转换? GHC 的本机代码生成器对于已知除数的除法非常愚蠢——我很确定它只能处理 2 的幂。
  • 当我说大数时,我的意思是整数。 quotRemInt 更快,但即使使用 -fllvm,你也无法获得较大的 integer 的数字。
【解决方案2】:

这是基于 No_signal 的 excellent approach,但在不分配任何不必要的结构的情况下对运行进行了一些小优化。为了加快速度,请使用-fllvm 进行编译——GHC 的本机代码生成器在优化除数除数方面做得不好。

hasAllDigits :: Int -> Bool
hasAllDigits = go 0x3FF where
 go !_set 0 = False
 go set n = case (clearBit set r) of
    0    -> True
    set' -> go set' q
   where
     (q,r) = n `quotRem` 10

【讨论】:

    【解决方案3】:

    没有理由说列表对于您的目的来说效率极低。您可以使用集合来跟踪您看到的数字。

    import Data.List 
    import qualified Data.Set as S
    
    digits = foldr S.insert S.empty . unfoldr go where 
      go 0 = Nothing 
      go n = let (a,b) = n `divMod` 10 in Just (b,a) 
    
    hasAll10Digits = (== (S.fromList [0..9])) . digits
    

    insert for Data.Set 是 O(log n),但是您要插入的集合永远不会超过 10 个元素,因此这些插入基本上是常数时间。

    【讨论】:

      猜你喜欢
      • 2013-11-20
      • 1970-01-01
      • 2022-06-30
      • 2013-06-25
      • 1970-01-01
      • 1970-01-01
      • 2015-02-07
      • 2010-12-19
      相关资源
      最近更新 更多