Find the sum of the digits of all numbers from 1 to N

Problem: Find the sum of the digits of all numbers from 1 to N (including both ends)

Time complexity should be O (logN)

At N = 10, the sum is 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + (1 + 0) = 46

At N = 11, the sum is 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + (1 + 0) + (1 + 1) = 48

At N = 12, the sum is 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + (1 + 0) + (1 + 1) + (1 + 2) = 51

This recursive solution works like a charm, but I would like to understand the rationale for achieving such a solution. I believe this is based on finite induction, but can anyone show exactly how to solve this problem?

I inserted (with slight modifications) the above solution:

static long Solution(long n)
{
    if (n <= 0)
        return 0;
    if (n < 10)
        return (n * (n + 1)) / 2; // sum of arithmetic progression
    long x = long.Parse(n.ToString().Substring(0, 1)); // first digit
    long y = long.Parse(n.ToString().Substring(1)); // remaining digits
    int power = (int)Math.Pow(10, n.ToString().Length - 1);

    // how to reach this recursive solution?
    return (power * Solution(x - 1))
    + (x * (y + 1)) 
    + (x * Solution(power - 1)) 
    + Solution(y);
}

Unit test (this is NOT O (logN)):

    long count = 0;
    for (int i=1; i<=N; i++)
    {
        foreach (var c in i.ToString().ToCharArray())
            count += int.Parse(c.ToString());
    }

Or:

Enumerable.Range(1, N).SelectMany(
    n => n.ToString().ToCharArray().Select(
        c => int.Parse(c.ToString())
    )
).Sum();
+4
2

O(n^log10(2)) -time (log10(2) 0.3). , . n = xy, , . .

return (power * Solution(x - 1))

x 1 x*power exclusive. , .

+ (x * (y + 1))

x x*power n .

+ (x * Solution(power - 1))

1 x*power exclusive. n.

+ Solution(y);

x*power n . n.

1 . O(log n), Solution(power - 1) . , .

+2

( ), , , .


S (n) - 0 <= k < .
D (k) - k.
( > , Dx = D (x)

n >= 10, n, (n = 10 * k + r) (k, r - )

S (n) = S (10 * k + r) = S (10 * k) + D (10 * k + 1) +... + D (10 * k + r)

S (10 * k) :
S (10 * 1) = D1 + D2 + D3 +... + D9 = (1 + 2 + 3 +... + 9) * 1 + D10
S (10 * 2) = D1 + D2 + D3 +... + D19 = (1 + 2 + 3 +... + 9) * 2 + 1 * 9 + D10 + D20
S (10 * 3) = D1 + D2 + D3 +... + D29 = (1 + 2 + 3 +... + 9) * 3 + 1 * 9 + 2 * 9 + D10 +... + D20 + D30

So S (10 * k)= (1 + 2 + 3 +... + 9) * k + 9 * S (k-1) + S (k-1) + D (10 * k) = 45 * k + 10 * S (k-1) + D (10 * k)

, D (10 * k + x) = D (10 * k) + D (x) = D (k) + x, :

D (10 * k + 1) +... + D (10 * k + r) = D (k) +1 + D (k) +2 +... D (k) + r = rD (k) + (1 + 2 +... + r) = rD (k) + r * (1 + r)/2

, ( D (k)), : S (n) = 45 * k + 10 * S (k-1) + (1 + r) D (k) + r * (1 + r)/2

k r, :
S (n) = 45 * k + 10 * S ((n/10) -1) + (1 + n% 10) D (n/10) + n% 10 (1 + n% 10)/2

S(n):
  if n=0, sum=0
  if n<10, n*(1+n)/2
  r=n%10 # let decompose n = 10*k + r (being k, r integers). 
  k=n/10
  return 45*k + 10*S((n/10)-1) + (1+n%10)*D(n/10) + n%10*(1+n%10)/2
D(n):
  just sum digits

( ) #

static BigInteger Solution(BigInteger n)
{
    if (n <= 0)
        return 0;
    if (n < 10)
        return (n * (n + 1)) / 2; // sum of arithmetic progression
    long x = long.Parse(n.ToString().Substring(0, 1)); // first digit
    long y = long.Parse(n.ToString().Substring(1)); // remaining digits
    BigInteger power = BigInteger.Pow(10, n.ToString().Length - 1);
    var log = Math.Round(BigInteger.Log10(power)); // BigInteger.Log10 can give rounding errors like 2.99999

    return (power * Solution(x - 1)) //This counts the contribution of the x place for the numbers from 1 inclusive to x*power exclusive. This recursive call doesn't contribute to the complexity because it returns in constant time.
    + (x * (y + 1)) //This counts the contribution of the x place for the numbers from x*power inclusive to n inclusive.
    //+ (x * Solution(power - 1)) // This counts the contribution of the lower-order places for the numbers from 1 inclusive to x*power exclusive. This call is on a number one digit shorter than n.
    + (x * 45*new BigInteger(log)* BigInteger.Pow(10,(int)log-1)) // 
    + Solution(y);
}

( ) #

static BigInteger Solution2(BigInteger n)
{
    if (n <= 0)
        return 0;
    if (n < 10)
        return (n * (n + 1)) / 2; // sum of arithmetic progression
    BigInteger r = BigInteger.ModPow(n, 1, 10); // decompose n = 10*k + r
    BigInteger k = BigInteger.Divide(n, 10);
    return 45 * k
         + 10*Solution2(k-1)                      // 10*S((n/10)-1)
         + (1+r) * (k.ToString().ToCharArray().Select(x => int.Parse(x.ToString())).Sum()) //  (1+n%10)*D(n/10)
         + (r * (r + 1)) / 2;                     //n%10*(1+n%10)/2
}

EDIT. , , ( ), Solution (power-1) .

PS: , , first last, , .

0

All Articles