数字之和直到作为输入给出的数字

时间:2012-09-11 14:02:47

标签: algorithm

如果给出一个数字作为输入,则找到所有数字的总和,直到该数字为

例如11输入然后答案是1 + 2 .... + 9+(1 + 0)+(1 + 1) 蛮力方法是计算小于数字的所有数字的数字之和。我已经实现了该方法,我想知道是否有任何其他方法可以在不实际计算每个数字的数字总和的情况下

2 个答案:

答案 0 :(得分:9)

您可以更快地完成此操作(在O(log n)操作中)。设S(n)为所有数字0 <= k < n的数字之和。然后

S(10*n) = 10*S(n) + 45*n

因为在小于10*n的数字中,每个k < n显示为数字的初始部分10次,最后一位数为0, 1, ..., 9。因此,对最后一位数的总和贡献45,对k的数字总和贡献10倍。

反过来,我们找到了

S(n) = 10*S(n/10) + 45*(n/10) + (n%10)*DS(n/10) + (n%10)*((n%10)-1)/2

其中DS(k)k的普通数字总和。前两个术语来自上面,其余两个来自n - n%10, ..., n - n%10 + (n%10 + 1)的数字之和。

S(n) = 0的开始时间为n <= 1

要包含上限,请将其命名为S(n+1)

答案 1 :(得分:-1)

我们举几个例子。

  

sum(9)= 1 + 2 + 3 + 4 ........... + 9          = 9 * 10/2          = 45

     

总和(99)= 45 +(10 + 45)+(20 + 45)+ .....(90 + 45)            = 45 * 10 +(10 + 20 + 30 ... 90)            = 45 * 10 + 10(1 + 2 + ... 9)            = 45 * 10 + 45 * 10            = sum(9)* 10 + 45 * 10

     

总和(999)=总和(99)* 10 + 45 * 100

一般情况下,我们可以使用以下公式计算总和(10d - 1)

  

总和(10d - 1)=总和(10d-1 - 1)* 10 + 45 *(10d-1)

在以下实现中,由于存在重叠的子问题,因此使用动态编程来实现上述公式。 上述公式是该想法的核心步骤之一。以下是完整的算法

  

算法:sum(n)

     

1)在n中找到数字减去1。让这个值为&#39; d。#   对于328,d为2。

     

2)计算从1到10d的数字中的一些数字 - 1.让这个   总和是。对于328,我们使用计算从1到99的数字之和   以上公式。

     

3)在n中找到最高有效位(msd)。对于328,msd为3。

     

4)总和是以下术语的总和

a) Sum of digits in 1 to "msd * 10d - 1".  For 328, sum of 
   digits in numbers from 1 to 299.
    For 328, we compute 3*sum(99) + (1 + 2)*100.  Note that sum of
    sum(299) is sum(99) + sum of digits from 100 to 199 + sum of digits
    from 200 to 299.  
    Sum of 100 to 199 is sum(99) + 1*100 and sum of 299 is sum(99) + 2*100.
    In general, this sum can be computed as w*msd + (msd*(msd-1)/2)*10d

b) Sum of digits in msd * 10d to n.  For 328, sum of digits in 
   300 to 328.
    For 328, this sum is computed as 3*29 + recursive call "sum(28)"
    In general, this sum can be computed as  msd * (n % (msd*10d) + 1) 
    + sum(n % (10d))

以下是上述aglorithm的C ++实现。

// C++ program to compute sum of digits in numbers from 1 to n
#include<bits/stdc++.h>
using namespace std;

// Function to computer sum of digits in numbers from 1 to n
// Comments use example of 328 to explain the code
int sumOfDigitsFrom1ToN(int n)
{
    // base case: if n<10 return sum of
    // first n natural numbers
    if (n<10)
      return n*(n+1)/2;

    // d = number of digits minus one in n. For 328, d is 2
    int d = log10(n);

    // computing sum of digits from 1 to 10^d-1,
    // d=1 a[0]=0;
    // d=2 a[1]=sum of digit from 1 to 9 = 45
    // d=3 a[2]=sum of digit from 1 to 99 = a[1]*10 + 45*10^1 = 900
    // d=4 a[3]=sum of digit from 1 to 999 = a[2]*10 + 45*10^2 = 13500
    int *a = new int[d+1];
    a[0] = 0, a[1] = 45;
    for (int i=2; i<=d; i++)
        a[i] = a[i-1]*10 + 45*ceil(pow(10,i-1));

    // computing 10^d
    int p = ceil(pow(10, d));

    // Most significant digit (msd) of n,
    // For 328, msd is 3 which can be obtained using 328/100
    int msd = n/p;

    // EXPLANATION FOR FIRST and SECOND TERMS IN BELOW LINE OF CODE
    // First two terms compute sum of digits from 1 to 299
    // (sum of digits in range 1-99 stored in a[d]) +
    // (sum of digits in range 100-199, can be calculated as 1*100 + a[d]
    // (sum of digits in range 200-299, can be calculated as 2*100 + a[d]
    //  The above sum can be written as 3*a[d] + (1+2)*100

    // EXPLANATION FOR THIRD AND FOURTH TERMS IN BELOW LINE OF CODE
    // The last two terms compute sum of digits in number from 300 to 328
    // The third term adds 3*29 to sum as digit 3 occurs in all numbers 
    //                from 300 to 328
    // The fourth term recursively calls for 28
    return msd*a[d] + (msd*(msd-1)/2)*p +  
           msd*(1+n%p) + sumOfDigitsFrom1ToN(n%p);
}

// Driver Program
int main()
{
    int n = 328;
    cout << "Sum of digits in numbers from 1 to " << n << " is "
         << sumOfDigitsFrom1ToN(n);
    return 0;
}

输出

Sum of digits in numbers from 1 to 328 is 3241