最小的数字可被10 ^ n整除,其中数字总计为n - Haskell

时间:2018-02-13 14:33:11

标签: haskell functional-programming

我需要做这个程序:

minor :: Integer -> Integer

这样(次要n)是可被10 ^ n整除的最小数字,其数字加起来为n。例如,

minor 5   ==  500000
minor 20  ==  29900000000000000000000
length (show (minor 67^35+3)) == a

我试过这个

minor :: Integer -> Integer
minor n = minimum [x | x <- [n*10^n..], rem x 10^n == 0, sum (digits x) == n]

digits :: Integer -> [Integer]
digits n = [read[d] | d <- show n]

但效率非常低,因为计算机卡住了。他们会怎么做?感谢。

3 个答案:

答案 0 :(得分:4)

有两个关键的观察结果可以解决这个问题:

  1. 该号码始终以n零结尾。
  2. 其余数字均为9(可能是第一位数字除外)。
  3. 这意味着您可以通过除以9找到9的数量,并且您可以使用该部门的余数找到最左边的数字。

     20 = 2 + (2 * 9) = 2 + 9 + 9      ⇒ 299
     35 = 8 + (3 * 9) = 8 + 9 + 9 + 9  ⇒ 8999
    

    在Haskell中,您可以使用quotRem除以9并同时获取商和余数。然后,您可以使用这些数字来构造输出编号。

    minor :: Integer -> Integer
    minor n = ((r + 1) * (10 ^ q) - 1) * (10 ^ n)
        where (q, r) = n `quotRem` 9
    

    如果您只想计算输出中的位数,可以通过观察作为minor的指数的10部分来找出,即{{1} }和q。如果n不是r,您可以添加0个数字。

    1

答案 1 :(得分:2)

您可以直接计算数字未成年人的小数位数,如果您想知道大输入的未成年人中的位数,这一点非常重要。

Willem描述了第一个主要技巧:一个数字的次要是一个数字,然后是一堆9,然后是一堆0。由于我们只关心有多少,我们可以直接计算这些东西。

numLeadingDigits n = signum (n `mod` 9)
num9s n = n `div` 9
num0s n = n

现在完整的长度只是这些的总和。

numDigitsInMinor n = numLeadingDigits n + num9s n + num0s n

这确实可以在巨大的投入上运行:

> numDigitsInMinor (67^35 + 3)
9086059680492581695084814449385436459012675694436486492711692052

明确地计算这个未成年人将需要10 ^ 63字节的内存,比人类在历史上所产生的总存储量高出许多个数量级。

答案 2 :(得分:1)

计算最小数

我们首先要考虑如何找到这样的数字,而不是使用强力算法。

10 n 分开的数字 n 拖尾零。例如,对于 n = 3 ,则数字为1000,2000,3000等。

接下来我们要找到最小这意味着我们控制的数字(最后 n 之前的数字应该在尾部尽可能大,为了小领先)。数字限制在0到9之间。

所以我们可以找到数字总和为 n 的最小数字:

smallest_sum :: (Num n, Ord n) => n -> n
smallest_sum 0 = 0
smallest_sum x = d + 10 * smallest_sum (x - d)
    where d = min 9 x

所以这里d = min 9 x是我们计算的数字,前面的数字是用递归计算的。

所以现在满足这些约束的最小数字是:

minor :: Integral i => i -> i
minor n = smallest_sum n * 10 ^ n

因此,这可以在线性时间内使用n

示例:

Prelude> minor 5
500000
Prelude> minor 20
29900000000000000000000
Prelude> minor 0
0
Prelude> minor 1
10
Prelude> minor 2
200
Prelude> minor 3
3000
Prelude> minor 4
40000
Prelude> minor 5
500000
Prelude> minor 6
6000000
Prelude> minor 7
70000000
Prelude> minor 8
800000000
Prelude> minor 9
9000000000
Prelude> minor 10
190000000000

该数字的长度

但是,就像@DanielWagner所说,这将不足以计算长度,因为这个数字将是巨大的:对于67^35+3,它将包含大约10 ^ 64位,这不能存储在内存中。关键是我们必须计算数字本身才能计算长度,我们可以用以下公式推导出长度:

length_minor :: Integral i => i -> i
length_minor n = length_smallest_sum n + n
    where length_smallest_sum n = div (n+8) 9

因此计算它的非常紧凑的函数是:

length_minor :: Integral i => i -> i
length_minor n = div (n+8) 9 + n

甚至更紧凑(但如果我们使用小整数表示,对溢出有点危险):

length_minor :: Integral i => i -> i
length_minor n = div (10*n+8) 9