頁碼統(tǒng)計(jì)

問題描述

牛牛新買了一本算法書,算法書一共有n頁,頁碼從1到n。牛牛于是想了一個(gè)算法題目:在這本算法書頁碼中0~9每個(gè)數(shù)字分別出現(xiàn)了多少次?

輸入描述

輸入包括一個(gè)整數(shù)n(1 ≤ n ≤ 1,000,000,000)

輸出描述

輸出包括一行10個(gè)整數(shù),即0~9這些數(shù)字在頁碼中出現(xiàn)的次數(shù),以空格分隔。行末無空格。

輸入例子

999

輸出例子

189 300 300 300 300 300 300 300 300 300

分析

參考《編程之美》和《劍指offer》的算法。

假設(shè)一個(gè)數(shù)N被表示為XDY,X和Y都是一串?dāng)?shù)字,長度為[0-∞];D是一個(gè)數(shù)字,大小為[0-9]。要注意的是,當(dāng)X的長度為0,即D是最高位數(shù)字時(shí),D不能為0。

現(xiàn)在要分析[1-N]這N個(gè)數(shù)在D位上出現(xiàn)數(shù)字d的次數(shù)C。我們可以舉一個(gè)具體的例子,當(dāng)X=12,Y=56時(shí),N=12D56,設(shè)d=1。根據(jù)D的大小情況,分下面三種情況討論:

  • D < 1
    即D=0,此時(shí)在D位上出現(xiàn)1的情況有:100-199,1100-1199,2100-2199,...,11100-11199,總共1200個(gè);

  • D = 1
    此時(shí)在D位上出現(xiàn)1的情況有:100-199,1100-1199,2100-2199,...,11100-11199,12100-12156,總共1200+156+1個(gè);

  • d > 1
    此時(shí)在D位上出現(xiàn)1的情況有:100-199,1100-1199,2100-2199,...,11100-11199,12100-12199,總共1300個(gè);

設(shè)Y的位數(shù)為pY。至此我們可以得出結(jié)論:當(dāng)D<1時(shí),C=X10^pY;當(dāng)D=1時(shí),C=X10pY+Y+1;當(dāng)D>1時(shí),C=(X+1)*10pY。

同理,這個(gè)結(jié)論對(duì)d∈[1,9]都適用。當(dāng)d=0時(shí),pY項(xiàng)改成pY-1即可。因?yàn)?不能作為最高項(xiàng)。例如上面D的三種情況,如果d=1,每種情況都有100-199;但是如果d=0,則不能出現(xiàn)000-099,這樣就正好少了X*10項(xiàng)。

note

  1. 多列幾個(gè)具體的例子,找找規(guī)律;
  2. 要善于分類討論。

代碼

字符串處理后轉(zhuǎn)數(shù)字

#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

long long countDigit(const string &str, int i, int j)
{
    int p = str.size() - i;
    int d = str[p - 1] - '0';

    string upperStr = str.substr(0, p - 1);
    string lowerStr = str.substr(p, i);

    long long upperNum = upperStr.empty() ? 0 : stoll(upperStr);
    long long lowerNum = lowerStr.empty() ? 0 : stoll(lowerStr);

    if (j == 0) upperNum--;

    if (d < j)
        return upperNum * pow(10, i);
    if (d == j)
        return upperNum * pow(10, i) + lowerNum + 1;
    return (upperNum + 1) * pow(10, i);
}

int main()
{
    char str[11];
    scanf("%s", str);
    string num(str);

    vector<long long> cnt(10, 0);
    for (int i = 0; i < num.length(); i++)
        for (int j = 0; j < 10; j++)
            cnt[j] += countDigit(str, i, j);

    printf("%d", cnt[0]);
    for (int i = 1; i < 10; i++)
        printf(" %d", cnt[i]);

    return 0;
}

數(shù)字計(jì)算

#include<iostream>

using namespace std;

int count(int n, int x) 
{
    int cnt = 0;
    for (int i = 1, j; j = n / i; i *= 10) 
    {
        int high = j / 10;
        int low = n - j * i;
        int digit = j % 10;

        if (x == 0) high--;

        cnt += high * i;
        if (digit > x)
            cnt += i;
        else if (digit == x)
            cnt += low + 1;
    }

    return cnt;
}

int main() 
{
    int n;
    cin >> n;

    cout << count(n, 0);
    for (int i = 1; i <= 9; i++)
        cout << " " << count(n, i);

    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容