1. 程式人生 > >從1到N的整數中1出現的次數

從1到N的整數中1出現的次數

題目:輸入一個整數N,輸出從1到N所有整數中1的個數。例如,輸入數10,輸出為2。

解題思路一:遍歷從1到N的所有數字,求出每個數中1的個數,然後累加起來,就是最終的結果。

程式碼實現:

//求出每個數中1的個數
int NmberOfI(unsigned int n)
{
    int number = 0;
    while (n)
    {
        if (n % 10 == 1)
        {
            number++;
        }
        n /= 10;
    }
    return number;
}
//求1到N所有整數中1的個數
int NumberOfOne(unsigned int n) { int number = 0; for (size_t i = 1; i <= n; i++) { number += NmberOfI(i); } return number; }

對於上邊的程式碼,假設每個數中有N個1,那麼它的時間複雜度為O(n*n)。因為上述程式碼對於每個數都進行了除或者模運算,效率比較低。

解題思路二:以計算1-21345中的1的個數為例。把這段數分為1-13451346-21345兩段計算。

  • 1.首先,我們先計算10000-19999
    這段中1的個數。分成兩種情況,如果給的數超過20000,存在10000-19999這段,則1的個數為10000個;另一種情況是所給的數沒有超過20000,比如說12345,那麼在這段中1的個數則為2345+1=2346
  • 2.第二步,我們計算1346-21345這段中要多少個1。因為10000-19999的萬位已經計算過了,那麼就只剩下後邊的四位了。因為這段既存在以1位萬位的,也存在以2位萬位的,所以我們可以把1346-21345分成兩段1346-1134511346-21345。在每一段中,萬位1的個數已經確定,剩下的四位,先確定一位為1,總共四種可能,剩下的三位取值在0-9,所以總共1的個數為2*4*10^3=8000種
  • 3.最後一步,是求1-1345這段
    ,這段上邊問題的子問題,是一個遞迴的問題。可以分成1-345346-1345兩端計算,顯然這裡可以用遞迴解決。

程式碼實現:

int PowerBase10(unsigned int n)
{
    int result = 1;
    for (unsigned int i = 0; i < n; i++)
    {
        result *= 10;
    }
    return result;
}
int NmberOfI_op(const char* str)
{
    assert(str);
    if (*str<'0' || *str>'9' || *str == '\0')
        return 0;
    int first = *str - '0';
    int len = strlen(str);

    if (len == 1 && first == 0)
        return 0;
    if (len == 1 && first > 0)
        return 1;

    //1.以21345為例,第一段10000-19999
    int numfirstdigit = 0;
    //第一個數大於2,則萬位有10000個1
    if (first > 1)
        numfirstdigit = PowerBase10(len - 1);
    //第一個數等於1,則萬位有後邊幾位的數+1(12345萬位位1有2346個)
    else if (first == 1)
        numfirstdigit = atoi(str + 1) + 1;
    //2.1346-21345(剩下的4位,1的位置可以有四種情況,1固定好之後,其他位有0-9十種情況,既4*10^3)
    //但是1346-21345應該分為兩端1346-11345、11346-21345,所以是8*10^3個
    int numotherdigit = first*(len - 1)*PowerBase10(len - 2);
    //3.0-1035(和上述方法一樣,採用遞迴解決)
    int numrecursion = NmberOfI_op(str + 1);
    //最後1的個數是前三步的和
    return numfirstdigit + numotherdigit + numrecursion;
}
//將數字轉換為字串方便計算
int NumberOfOne_op(int n)
{
    if (n <= 0)
        return 0;
    char str[50];
    //將一些內容格式化輸入到字串中
    sprintf(str, "%d", n);
    return NmberOfI_op(str);
}