1. 程式人生 > >求1~n中0~9出現的次數

求1~n中0~9出現的次數

題目來至牛客網:頁碼統計
牛牛新買了一本演算法書,演算法書一共有n頁,頁碼從1到n。牛牛於是想了一個演算法題目:在這本演算法書頁碼中0~9每個數字分別出現了多少次?
輸入描述:

輸入包括一個整數n(1 ≤ n ≤ 1,000,000,000)

輸出描述:

輸出包括一行10個整數,即0~9這些數字在頁碼中出現的次數,以空格分隔。行末無空格。
示例1
輸入

999
輸出

189 300 300 300 300 300 300 300 300 300

解法一

暴力破解
public static void main(String[] args) {
        // TODO Auto-generated method stub
Scanner cin = new Scanner(System.in); int n = cin.nextInt(); int res[] = new int[10]; for (int i = 1; i <=n; i++) { count(res, i); } for (int i = 0; i < 10; i++) { if (i != 0) { System.out.print(" "); } System.out
.print(res[i]); } } //依次每一位求解:因為一個數i的時間複雜度為log(n),有n個數,所以總體時間複雜度是:nlog(n)。 public static void count(int res[], int n) { //雖然簡單明瞭,但是複雜度太高 while (n != 0) { res[n % 10]++; n /= 10; } }

解法二

數字規律

拿123舉例,假設需要求1出現的個數,我們可以計算每一位上出現的個數。假設1出現在個位時數的格式是XX1 ,前面的XX能組成的個數就是1在個位時出現的次數。XX可以組成00~12共13個數。所以1在個位出現13次。當1在十位時,X1X,則可以組成(0~1)*(0~9)種,為什麼是0~9呢?因為十位為1時能組成的最大數是119,小於123所以個位可以是0~9。如果我們是求2的次數的話就需要另外判斷了,因為格式為12X能組成的數最大是123,不能是124~129,所以,只需要判斷一下當前位的數和需要求出現次數的數之間的關係即可。
程式碼如下:

/**
**  num:代表題目中的n ,target:需要統計的數
**/
public static int getCount(int num, int target) {
        //表示當前的位數(個位、十位。。。)
        int base = 1;
        //結果
        int sum = 0;
        int n = num;

        while (n != 0) {
            //以123為例,當1在個位時sum+= 1*12,並沒有加13是因為我們還沒有判斷當前位的數cur跟要求的數的關係。
            sum += base * (n / 10);
            //cur當前位的數如123中個位的數是3
            int cur = n % 10;

            if (cur == target) {
            //當cur等於target,比如123,處於十位時求2出現的次數,因為只能有120~123四種情況所以,對應sum += num % base + 1
                sum += num % base + 1;
            } else if (cur > target) {
                //當cur大於target,比如123,處於個位時求1出現的次數,需要加上12開頭的情況,所以sum += 1 * base。
                sum += 1 * base;
            }else if(cur<target){
                //當cur小於target,比如123,處於個位時求5出現的次數,這是125是不成立的。
            }

            base *= 10;
            n = n / 10;
        }

        return sum;

    }

上述程式碼只能處理1~9的情況,當求0出現的次數時需要額外考慮,比如00X和0X0以及0XX都是0,這顯然不在題目的考慮範圍之類,所以,只需要將這種情況去掉即可:
程式碼如下:

public static int getCount0(int num) {

        int base = 1;
        int sum = 0;
        int n = num;

        while (n != 0) {
            //區別在於這一行程式碼,減掉了1
            sum += base * (n / 10 - 1);

            int cur = n % 10;
            if (cur == 0) {
                sum += num % base + 1;
            } else if (cur > 0) {
                sum += base;
            }

            base *= 10;
            n = n / 10;
        }

        return sum;

    }

所以,牛客課網題目的答案如下:

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();

        int res[] = new int[10];

        res[0] = getCount0(n);
        for (int i = 1; i < 10; i++) {
            res[i] = getCount(n, i);
        }

        for (int i = 0; i < 10; i++) {
            if(i!=0){
                System.out.print(" ");
            }
            System.out.print(res[i]);
        }

    }

    public static int getCount(int num, int target) {

        int base = 1;
        int sum = 0;
        int n = num;

        while (n != 0) {

            sum += base * (n / 10);

            int cur = n % 10;
            if (cur == target) {
                sum += num % base + 1;
            } else if (cur > target) {
                sum += base;
            }

            base *= 10;
            n = n / 10;
        }

        return sum;

    }

    public static int getCount0(int num) {

        int base = 1;
        int sum = 0;
        int n = num;

        while (n != 0) {

            sum += base * (n / 10 -1);

            int cur = n % 10;
            if (cur == 0) {
                sum += num % base + 1;
            } 
            else if (cur > 0) {
                sum += base;
            }

            base *= 10;
            n = n / 10;
        }

        return sum;

    }
}

當然,也可以參考這篇部落格:經典的數1問題