233. 數字1的個數
阿新 • • 發佈:2018-12-02
給定一個整數 n,計算所有小於等於 n 的非負整數中數字 1 出現的個數。
示例:
輸入: 13 輸出: 6 解釋: 數字 1 出現在以下數字中: 1, 10, 11, 12, 13 。
解題思路:
1.參考:https://www.cnblogs.com/grandyang/p/4629032.html
通過上面的列舉我們可以發現,100以內的數字,除了10-19之間有11個‘1’之外,其餘都只有1個。如果我們不考慮[10, 19]區間上那多出來的10個‘1’的話,那麼我們在對任意一個兩位數,十位數上的數字(加1)就代表1出現的個數,這時候我們再把多出的10個加上即可。比如56就有(5+1)+10=16個。如何知道是否要加上多出的10個呢,我們就要看十位上的數字是否大於等於2,是的話就要加上多餘的10個'1'。那麼我們就可以用(x+8)/10來判斷一個數是否大於等於2。
對於三位數區間 [100, 199] 內的數也是一樣,除了[110, 119]之間多出的10個數之外,共21個‘1’,其餘的每10個數的區間都只有11個‘1’,所以 [100, 199] 內共有21 + 11 * 9 = 120個‘1’。那麼現在想想[0, 999]區間內‘1’的個數怎麼求?根據前面的結果,[0, 99] 內共有20個,[100, 199] 內共有120個,而其他每100個數內‘1’的個數也應該符合之前的規律,即也是20個,那麼總共就有 120 + 20 * 9 = 300 個‘1’。
程式碼:
class Solution { public: int countDigitOne(int n) { int res = 0, a = 1, b = 1; while (n > 0) { res += (n + 8) / 10 * a + (n % 10 == 1) * b; b += n % 10 * a; a *= 10; n /= 10; } return res; } };
對於(x+8)/10的理解:考慮res += (n + 8) / 10 * a + (n % 10 == 1) * b; n>=2和n<2會造成一個a的區別,a可以理解為個位、十分位、百分位等上1的個數,所以結合上面的描述,就是說尾數>=2的時候,就會有額外的1出現。關於這塊可結合下面的解法。
2.參考:https://blog.csdn.net/geekmanong/article/details/51050854
利用數學歸納法,直接對n進行分析,歸納總結規律
例如n=abcde五位數,我們分析百位的c,主要有以下三種情況:
1)當c == 0的時候,比如13013,此時百位出現1的是:00 100 ~ 00 199, 01 100~01 199,……,11 100~ 11 199,12100~12199共1300個,顯然這個由高位數字決定,並且受當前位數影響,結果為:(高位數字)乘以(當前位數);
2)當c == 1的時候,比如13113,此時百位出現1的肯定包括c=0的情況,另外還需要考慮低位的情況即:00100 ~ 00113共114個,結果為:(高位數字)乘以(當前位數)+(低位數字)+1;
3)當c >= 2的時候,比如13213,此時百位出現1的是:00 100 ~ 00 199, 01 100~01 199,……,11 100~ 11 199,12 100 ~ 12 199,13100~13199,共1400個,這個僅由高位數字決定,結果為:(高位數字+1)乘以當前位數。
程式碼:
class Solution { public: int countDigitOne(int n) { if (n <= 0) return 0; long count = 0; long factor = 1; while (n / factor) { long lower = n%factor; long cur = (n / factor) % 10; long higher = n / (factor * 10); switch (cur) { case 0: count += higher*factor; break; case 1: count += higher*factor + lower + 1; break; default: count += (higher + 1)*factor; } factor *= 10; } return (int)count; } };