1. 程式人生 > 實用技巧 >整數中 1 出現的次數(從 1 到 n 整數中 1 出現的次數)

整數中 1 出現的次數(從 1 到 n 整數中 1 出現的次數)


求出 1 ~ 13 的整數中 1 出現的次數,並算出 100 ~ 1300 的整數中 1 出現的次數?可以發現 1 ~ 13 中包含 1 的數字有 1、10、11、12、13,因此共出現 6 次。現需要把問題更加普遍化,可以很快的求出任意非負整數區間中 1 出現的次數(從 1 到 n 中 1 出現的次數)


解題思路

設定整數點(1、10、100、1000、10000)分別對應 n 的個位、十位、百位、千位、萬位,我們要做的就是:考慮每一位出現 1 的情況,算出各自符合題意的數的數量,並進行相加,就能得出想要的結果。

現以整數點 100 為例,使用 100 對 n 進行分割,高位為 n/100,低位為 n%100

考慮三種情況:

  • 以 31456 為例,百位對應的數 4 >= 2,此時高位 a = 314,低位 b = 56,因為 4 >= 2,所以肯定會有百位為 1 的情況,此時無論其他位的數是多少,都將滿足題意。高位可以取 32 種情況(0 ~ 31),低位則總是 100 個連續的點,因此共有 (a/10 + 1)*100 個數
  • 以 31156 為例,百位對應的數 1 == 1,此時高位 a = 311,低位 b = 56,因為百位已經是 1,此時無論其他位的數是多少,都將滿足題意。高位的取值要分情況,當最高兩位範圍是 0 ~ 30 時,和上一條一樣;當 a = 311(取 31) 時,則對應的低位只有 0 ~ 56,共 b + 1 次,因此總共有 (a/10)*100 + (b + 1)
  • 以 31056 為例,百位對應的數為 0,此時高位 a = 310,低位 b = 56,百位為 0,所以高位的前兩位只能去 0 ~ 30,這樣百位才能取 1,因此總共有 (a/10)*100

綜合以上三種情況,我們可以得出:

  • 當百位 == 0 或 >= 2 時,有 (a+8)/10 次包含所有 100 個點(之所以補 8,是因為當百位為 0,則 a/10 == (a+8)/10,當百位 >= 2,補 8 會產生進位位,效果等同於 (a/10+1))
  • 當百位 == 1,即 (a%10==1),則需要增加區域性點 b+1
public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        int count = 0;
        long split = 1;
        for(int i = 1; i <= n; i *= 10) {
            int a = n/i, b = n%i;
            count = count + ((a+8)/10)*i + ((a%10 == 1) ? (b + 1) : 0);
        }
        return count;
    }
}