数量从101到10 ^ 60的“跳跃”数字?

时间:2012-10-12 15:27:59

标签: algorithm

如果数字按升序排列,则数字为“升序”。示例:1223469。“降序”数字的数字按降序排列。示例:9844300。不是“升序”或“降序”的数字称为“跳跃”。从1到100的数字不是“跳跃”。从101到10 ^ 60有多少“跳跃”数字?

4 个答案:

答案 0 :(得分:3)

这是一个想法:不是计算跳跃数,而是计算升序和降序数。然后从所有数字中减去它们。

计算上升/下降应该很容易 - 你可以根据剩下的数字生成动态编程,以及你放在最后位置的数字。

答案 1 :(得分:3)

我将描述如何计算递增数字,因为这样更容易。从那里开始,你也可以计算下降的数量,然后从总数量中减去合计数量,补偿重复,如Ivan所示,或者设计一种更复杂的方式来直接计算跳数。

一种不同的方法

考虑按结束数字排序的数字。我们从1位数的数字开始,这将是我们的列表

1 // Amount of numbers ending with 1
1 // Amount of numbers ending with 2
1 // Amount of numbers ending with 3
1 // Amount of numbers ending with 4
1 // Amount of numbers ending with 5
1 // Amount of numbers ending with 6
1 // Amount of numbers ending with 7
1 // Amount of numbers ending with 8
1 // Amount of numbers ending with 9

要构建两位数以6结尾的数字,我们可以使用所有以6或更少结尾的数字

1 // Amount of numbers ending with 1 with 2 digits
2 // Amount of numbers ending with 2 with 2 digits
3 // Amount of numbers ending with 3 with 2 digits
4 // Amount of numbers ending with 4 with 2 digits
5 // Amount of numbers ending with 5 with 2 digits
6 // Amount of numbers ending with 6 with 2 digits
7 // Amount of numbers ending with 7 with 2 digits
8 // Amount of numbers ending with 8 with 2 digits
9 // Amount of numbers ending with 9 with 2 digits

并排编写这些内容,可以看到如何快速计算新值:

y a // y,a和x之前已经计算过了 x(a + x)

1 1  1   1 
1 2  3   4
1 3  6  10
1 4 10  20
1 5 15  35
1 6 21  56
1 7 28  84
1 8 36 120
1 9 45 165 

一个简单的Python程序

迭代一个这样的列,如果我们总是记住最后一次计算,我们可以直接生成新列的所有值。 scan()函数完全抽象出取一个元素的行为,并用它和最后的结果做一些计算。

def scan(f, state, it):
  for x in it:
    state = f(state, x)
    yield state

现在,生成下一列就像:

一样简单
new_column = list(scan(operator.add, 0, column))

为简单起见,我们使用单个数字作为起点:

first_row = [1]*9

看到我们总是需要将新行反馈给该函数,可以再次使用scan来做到这一点:

def next_row(row):
    return list(scan(operator.add, 0, column))

def next_row_wrapper(row, _):
    return next_row(row)

>>> [list(x) for x in scan(next_row_wrapper, [1]*9, range(3))] # 3 iterations
[[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 3, 6, 10, 15, 21, 28, 36, 45], [1, 4, 10, 20, 35, 56, 84, 120, 165]]

正如您所看到的,这使得前三行与第一行不同。

由于我们想知道所有数字的总和,我们可以做到这一点。当我们进行1次迭代时,我们得到所有递增的数字直到10 ^ 2,所以我们需要对所有数字进行59次迭代,直到10 ^ 60:

>>> sum(sum(x) for x in scan(lambda x, _: next_row(x), [1]*9, range(59))) + 10
56672074888L

对于降序数字,它非常相似:

>>> sum(sum(x) for x in scan(lambda x, _: next_row(x), [1]*10, range(59))) + 10 - 58
396704524157L<

旧方法

想想数字如何结束:

从10到99,我们每个数字有两位数。

  • 1以1
  • 结尾
  • 2以2结尾
  • 3结束于3
  • 4以4结尾
  • 5结束于5
  • 6结束于6
  • 7结束于7
  • 8结束于8
  • 9结束于9

所有这些数字都作为100到999之间数字的前缀。

例如,有三个数字以3结尾:

  • 13
  • 23
  • 33

对于这三个数字中的每一个,我们可以创建七个递增数字:

  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139

很容易看出,这为七个可能的结束数字中的每一个添加了三个数字。

如果我们想要扩展以4结尾的数字,那么过程将类似:目前,有4个数字以4结尾。因此,对于每个这样的数字,我们可以创建6个新的递增数字。这意味着,对于所有六个可能的结束数字,将会有额外的4个。

如果你已经理解了我在这里写的所有内容,那么应该很容易概括并实现一种算法来计算所有这些数字。

答案 2 :(得分:1)

非跳数:

  • 69 choose 9(升序数量≤60)
  • + 70 choose 10 - 60(降序数量≤60)
  • - 60 * 9(重复计算:所有数字相同)
  • - 1(重复计数:零)
  • = 453376598563

(要获得跳跃数字,从总数中减去:10 60

计算数字的简单python程序:

# I know Python doesn't do tail call elimination, but it's a good habit.
def choose(n, k, num=1, denom=1):
  return num/denom if k == 0 else choose(n-1, k-1, num*n, denom*k)

def f(digits, base=10):
  return choose(digits+base-1, base-1) + choose(digits+base, base) - digits*base - 1

升序数字:从0开始,选择9个位置来递增数字。

降序数字:假装我们有一个数字10,用于左边填充数字。然后选择10个位置来减少数字,从10开始。然后删除10个选定位置连续而不是最后的所有选项,这将对应于前导0的数字序列。

由于所有数字都相同的数字都将由降序和递增算法产生,我们必须减去它们。

请注意,所有这些算法都认为数字0写入时根本没有数字。此外,所有数字≤100都是升序或降序(或两者),因此无需担心它们。

答案 3 :(得分:0)

您是将321计为下降还是将000000321视为跳跃?

提示答案:59位数的升序号码(69选10),因为你必须选择数字中哪些点位于不同的数字之间。