1. 程式人生 > >關於劍指offer上“從1到n整數中1出現的次數”題的理解

關於劍指offer上“從1到n整數中1出現的次數”題的理解

寫這篇部落格是因為,看完劍指offer上這道題的解釋後,我確實是沒有看懂。所以按照我的思路重新描述一下這道題到底要怎麼做。


題目描述:

輸入一個整數n,求從1到n這n個整數的十進位制表示中1出現的次數


首先想到的肯定是暴力法,這裡就不多說了。

更優化的方法需要我們先列舉幾個數來找找規律。

假設用i表示當前的數位

(1)當i位為0時,比如12034,顯然當前位是第三位,那麼第三位出現1的情況有哪些呢?

100~199

1100~1199

2100~2199

3100~3199

.....

10100~10199

11100~11199

一共是12*100 = 1200個數

也就是0的高位數12乘以當前位數(第三位的位數是100,第二位是10,以此類推)

(2)當第i位為1時,比如12134,那麼第三位出現1的情況有哪些?

100~199

1100~1199

2100~2199

3100~3199

.....

10100~10199

11100~11199

12100~12134

即12*100+(34+1) = 1235個數

也就是0的高位數12乘以當前位數100,然後加上低位數+1,得到的值

(3)當第i位大於1時,比如12433,那麼第三位出現1的情況有哪些?

100~199

1100~1199

2100~2199

3100~3199

.....

10100~10199

11100~11199

12100~12199

即13*100

也就是0的高位數+1然後乘以當前位數100

按照上述規律,對每一位求出現1的數,最後累加即可得到結果。


程式碼如下:

int NumberOf1Between1AndN_Solution(int n){
    int count = 0;  //1的個數
    int i=1;  //當前位
    int current = 0, after = 0, before = 0;

    //比如n=12345,i=100
    //current = 3
    //before = 12
    //after = 45
    while((n/i) != 0){
        current = (n/i) % 10;  //當前位的數字
        before = n/(i*10);  //當前位及之前的數字
        after = n - (n/i)*i;  //低位數字

        //如果當前位為0,出現1的次數由高位覺得,等於高位數字*當前位數
        if(current == 0){
            count += before * i;
        }else if(current == 1){
            //如果當前位為1,出現1的次數由高位和低位決定,高位*當前位+低位+1
            count += before*i + after + 1;
        }else{
            //如果大於1,出現1的次數由高位決定,(高位數字+1)*當前位數
            count += (before+1)*i;
        }
        //前移一位
        i = i * 10;
    }
    return count;
}

牛客網上可測試程式碼是否正確

https://www.nowcoder.com/questionTerminal/bd7f978302044eee894445e244c7eee6