本節給出的題目是:
給定一個十進制整數N,寫下從1開始,到N的所有整數,然後數一下其中出現的所有“1”的個數。
例如:
N = 2,寫下1, 2。出現1個“1”。
N = 12,寫下1, 2, 3,4,5,6,7,8,9,10,11,12。這樣,1的個數是5。
(1)寫一個函數f(N),返回1到N之間出現的“1”的個數。
(2)滿足條件f(N) = N的最大的N是多少。
書中給出的解法一是一般人看到這題就會想到的辦法,依次遍歷1到N的所有數,計算每個數字中的1的個數,然後累加。當然,這樣的結果是時間複雜度很差。
解法二首先按照N的位數來進行分類討論,然後再對各個位可能出現1的情況進行計算。
當N是1位數時:
比如N = 5,那麼,從1到5中只有個位可能出現1,而且只有1次,因此,對1位數就有,當N = 0時,f(N) = 0,當N>=1時,f(N) = 1。
當N是2位數時:
比如N = 30,那麼,十位和個位都可能出現1,個位出現1的情況有1,11,21,即個位出現1的次數等於N的十位上的數字,十位出現1的情況有10~19,爲10,總共出現1的個數是3 + 10 = 13。
比如N = 31,4 + 10 = 14。
也就是,對於某一位來說,如果該位爲0,那麼,在該位可能出現1的情況就是該位以前的數從0一直到該位以前的數減1,也就是該位以前的數乘以該位所在位的基。
如果該位爲1,那麼,除了上面爲0的情況,再加上該位爲1,並且該位之後的數從0到該位之後的數,也就是上面爲0的值加上該位之後的數再加1。
如果該位大於1,那麼,該位可能出現1的情況就是該位以前的數從0到該位以前的數,也就是該位以前的數加1,然後乘以所在位的基。
從上面分析,可以很容易得到下面的程序:
long sum1s(long n)
{
long icount = 0;
long ifactor = 1;
long ilowernum = 0;
long icurrnum = 0;
long ihighernum = 0;
while(n / ifactor) {
ilowernum = n - (n / ifactor) * ifactor;
icurrnum = (n / ifactor) % 10;
ihighernum = n / (ifactor * 10);
switch(icurrnum) {
case 0:
icount += ihighernum * ifactor;
break;
case 1:
icount += ihighernum * ifactor + ilowernum + 1;
break;
default:
icount += (ihighernum + 1) * ifactor;
break;
}
ifactor *= 10;
}
return icount;
}
關於問題2,有些還沒想明白,有空再看。