[編程之美] 2.4 1的個數

本節給出的題目是:

給定一個十進制整數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,有些還沒想明白,有空再看。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章