我试图找到具有一定数字位数的单调增加数字的数量。具有k
数字的单调递增数字可写为
n = a_0 a_1 ... a_k-1
所有a_i <= a_(i+1)
的{{1}}。更具体的示例是i in range(0, k)
或123
。我正在尝试创建一个这样的函数
12234489
因为有45个数字,两位数正在增加,increasing(2) = 45
increasing(3) = 165
increasing(4) = 495
increasing(5) = 1287
increasing(6) = 3003
。等等。
我认为这是使用递归的好机会。我试图编写一个执行此操作的代码,但结果有问题。我的psudo代码就像这样
11, 12, ..., 22, 23, ..., 88, 89, 99
开始循环显示这些数字。将[1, 2, ..., 9]
增加一个。length
,其中[i, ..., 9]
是前一次递归的数字。last_digit
向length = number of digits wanted
和total
添加一个,则重复上述步骤。 return
我的psudocode找到这些数字是否正确?如何正确使用递归来解决这个问题?
我不会要求在我的代码中找到错误,但是一些指针或代码的示例将非常有用。
答案 0 :(得分:4)
这可以以封闭的形式计算。
我们有8个单位的预算,我们可以分配给每个数字或者#34;剩余时间&#34;。分配给n
预算单位的数字比其前面的数字大n
;对于第一个数字,如果我们在那里分配n
个预算单位,则其值为n+1
。剩下的预算什么都不做。
预算分配与单调增加的数字一一对应,因为每个预算分配产生单调增加的数字,并且每个单调增加的数字具有相应的预算分配。因此,长度k
的单调增加数量的数量是将8个单位的预算分配给k+1
桶,每个数字一个桶和一个剩余桶的方式的数量。
根据经典stars and bars结果,这是(8 + k) choose 8
或(8+k)!/(8!k!)
:
def monotone_number_count(k):
total = 1
for i in xrange(k+1, k+9):
total *= i
for i in xrange(1, 9):
total //= i
return total
对于单调减少的数字,可以应用相同的想法。这次我们有9个预算单位,因为我们的数字可以从9下降到0,而不是从1开始,最多到9个。分配给n
预算单位的数字为n
低于前一个数字;对于第一个数字,n
预算单位为其赋予值9-n
。需要注意的是,这会将0000
计为四位数,对于k
的其他值也是如此,因此我们必须明确地将其取消,结果为((9 + k) choose 9) - 1
:
def monotonely_decreasing_number_count(k):
total = 1
for i in xrange(k+1, k+10):
total *= i
for i in xrange(1, 10):
total //= i
total -= 1
return total
答案 1 :(得分:3)
您可以使用基于以下关系的简单递归:从i开始的k个数字的单调数量的计数(0
对于k = 1,结果是微不足道的:10-i
这将导致以下递归函数:
def num_increasing(ndigits, first=1):
n = 0
if ndigits == 1:
n = 10 - first
else:
for digit in range(first, 10):
n += num_increasing(ndigits - 1, digit)
return n
对于ndigits = 6,它给出3003。
答案 2 :(得分:0)
这是一个非递归的解决方案:
def is_monotonic(num, reverse=False):
num = str(num)
# check if the string representation of num is same as the sorted one
return num == ''.join(sorted(num, reverse=reverse))
def get_monotonic_nums(ndigit, reverse=False):
start = 10**(ndigit-1) if reverse else int('1' * ndigit)
end = 10**ndigit
return sum(is_monotonic(num, reverse) for num in xrange(start, end))
然后用法:
>>> get_monotonic_nums(2)
45
>>> get_monotonic_nums(6)
3003
而且,如果您需要减少订单:
>>> get_monotonic_nums(2, reverse=True)
54
答案 3 :(得分:0)
这就是我想出来的;
def is_monotonic(n):
n = str(n)
for x, y in zip(n[:-1], n[1:]):
if x > y:
return False
return True
def get_monotonic_nums(digits):
digits = abs(digits)
start = 0 if digits == 1 else int('1{}'.format('0'*(digits-1)))
end = start * 10 if start else 10
for n in range(start, end):
if is_monotonic(n):
yield n
测试;
len(list(get_monotonic_nums(2)))
45
答案 4 :(得分:0)
在互联网上进行一些搜索后,我能够找出以下一个班轮解决方案。基于二项式系数的和公式。我现在意识到我的递归解决方案与这个解决方案相比有多慢。
def choose(n, k):
"""
A fast way to calculate binomial coefficients by Andrew Dalke (contrib).
"""
if 0 <= k <= n:
ntok = 1
ktok = 1
for t in xrange(1, min(k, n - k) + 1):
ntok *= n
ktok *= t
n -= 1
return ntok // ktok
else:
return 0
def increasing(digit):
return choose(digit + 9,9) - 1
def decreasing(digit):
return choose(digit + 10,10) - 10*digit - 1