function that counts...
superpollo
utente at esempio.net
Thu May 20 10:40:35 EDT 2010
Richard Thomas ha scritto:
> For this kind of problem you should avoid all that stringification. I
> find it best to deal with sequences of digits of a fixed length and go
> from there. For example:
>
> def count1(m, n, cache={}):
> """Number of digit sequences of length `n` summing to `m`."""
> if n < 0 or m < 0:
> return 0
> elif n == 0:
> return int(m == 0)
> elif (m, n) in cache:
> return cache[m, n]
> # This is an optimisation using the combinatoric choose function.
> #elif m < 10:
> # result = choose(n + m - 1, n - 1)
> else:
> result = 0
> for digit in xrange(min(10, m + 1)):
> result += count1(m - digit, n - 1)
> cache[m, n] = result
> return result
>
> Notice the caching of results. With this we can compute the required
> thing quite easily:
>
> def count2(m, n):
> """Number of numbers less than `n` whose digits sum to `m`."""
> result = 0
> digits = map(int, str(n))
> length = len(digits)
> for idx, digit in enumerate(digits):
> for seq_digit in xrange(digit):
> seq_limit = m - seq_digit
> seq_length = length - idx - 1
> result += count1(seq_limit, seq_length)
> m -= digit
> return result
>
> Essentially we move through the number left to right, choose digits
> less than the digit in the number and count digit sequences to fill
> the remainder. Then fix the actual digit and step forward.
>
> An approach like this avoids the relatively slow stringification
> process and makes decent use of caching and iteration (both easy and
> efficient in Python).
>
> In [1]: count2(25, 10000)
> Out[1]: 348
>
> In [2]: timeit count2(25, 10000)
> 100000 loops, best of 3: 12.6 us per loop
wow.
impressive, thanks.
More information about the Python-list
mailing list