給定乙個十進位制正整數 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。
問題是:
寫乙個函式f(n) 返回1到n之間出現的「1」的個數,比如f(12)=5。
這個問題看上去並不是乙個困難的問題,因為不需要太多的思考,大家都能找到乙個最簡單的方法來計算 f(n),那就
是從1開始遍歷到n,將其中每乙個數中含有「1」的個數加起來,
自然就得到了從1到n所有「1」的個數的和.c語言實現如下:
#include stdio.h
int count1(int n)
return inum;
}int count2(int n)
return icount;
}int main()
但是這個演算法的致命問題是效率,它的時間複雜度是o(n)×計算乙個整數數字裡面「1」的個數的複雜度 = o(n *log2 n),如果給定的 n 比較大,則需要很長的運算時間才能得到計算結果。
解法二《程式設計之美》先從一些簡單的情況開始觀察:
如果n是一位數,可以確定f(n)=1
如過是二位數,如果 n=13,那麼從 1 到 13 的所有數字:1、2、3、4、5、6、
7、8、9、10、11、12、13,個位和十位的數字上都可能有 1,我們可以將它們分開來考慮,個位出現 1 的次數有兩次:1 和 11,十位出現 1 的次數有 4 次:10、11、12 和 13,所以 f(n)=2+4=6。要注意的是 11 這個數字在十位和個位都出現了 1, 但是 11 恰好在個位為 1 和十位為 1 中被計算了兩次,所以不用特殊處理,是對的。再考慮 n=23 的情況,它和 n=13 有點不同,十位出現 1 的次數為 10 次,從 10 到 19,個位出現 1 的次數為 1、11 和 21,所以f(n)=3+10=13。
通過對兩位數進行分析,我們發現,個位數出現 1 的次數不僅和個位數字有關,還和十位數有關:如果 n 的個位數大於等於 1,則個位出現 1 的次數為十位數的數字加 1;如果n 的個位數為 0,則個位出現 1 的次數等於十位數的數字。而十位數上出現 1 的次數不僅和十位數有關,還和個位數有關:如果十位數字等於 1,則十位數上出現 1 的次數為個位數的數字加 1;如
果十位數大於 1,則十位數上出現 1 的次數為 10。
f(13) = 個位出現1的個數 + 十位出現1的個數 = 2 + 4 = 6;
f(23) = 個位出現1的個數 + 十位出現1的個數 = 3 + 10 = 13;
f(33) = 個位出現1的個數 + 十位出現1的個數 = 4 + 10 = 14;
…f(93) = 個位出現1的個數 + 十位出現1的個數 = 10 + 10 =
20;
接著分析 3 位數,
如果 n = 123:
個位出現 1 的個數為 13:1, 11, 21, …, 91, 101, 111, 121
十位出現 1 的個數為 20:10~19, 110~119
百位出現 1 的個數為 24:100~123
f(123)= 個位出現 1 的個數 + 十位出現 1 的個數 + 百位出現 1 的次數 = 13 + 20 + 24 = 57;同理我們可以再分析 4 位數、 位數。
根據上面的一些嘗試,下面我們推導出一般情況下,從 n 得
到 f(n)的計算方法:
假設 n=abcde,這裡 a、b、c、d、e 分別是十進位制數 n 的各個數字上的數字。如果要計算百位上出現 1 的次數,它將會受到三個因素的影響:百位上的數字,百位以下(低位)的數字,百
位(更高位)以上的數字。
如果百位上的數字為 0,則可以知道,百位上可能出現 1 的次
數由更高位決定,比如 12 013,則可以知道百位出現 1 的情況可能
是 100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,
一共有 1 200 個。也就是由更高位數字(12)決定,並且等於更高
位數字(12)×當前位數(100)。
如果百位上的數字為 1,則可以知道,百位上可能出現 1 的次數不僅受更高位影響,還受低位影響,也就是由更高位和低位共同決定。例如對於 12 113,受更高位影響,百位出現 1 的情況是 100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,一共 1 200個,和上面第一種情況一樣,等於更高位數字(12)×當前位數(100)。但是它還受低位影響,百位出現 1 的情況是 12 100~12 113,一共114 個,等於低位數字(123)+1。
如果百位上數字大於 1(即為 2~9),則百位上可能出現 1的次數也僅由更高位決定,比如 12 213,則百位出現 1 的可能性為:100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,12 100~12 199,一共有 1 300 個,並且等於更高位數字+1(12+1)
×當前位數(100)。
通過上面的歸納和總結,我們可以寫出如下的更高效演算法來
計算 f(n):
#include
int sumls(int n)
ifactor*=10;
}return icount;
}int main()
程式設計之美 1的數目
我一上來就是遍歷著計算,但在面試或者應用中決計是不可行的。我們換一種思路,乙個數abcdefg,我們計算出各位,十位,百位。有多少個1,加一起即可。就23012來說,看百位上它為0,從1 23012中,百 位上有多少個1取決於比它高的所有位決定。100 199,1100 1199,2100 2199...
程式設計之美 1的數目
給定乙個十進位制正整數n,寫下從1開始,到n的所有整數,然後數一下其中出現的所有 1 的個數。解法一 窮舉法,遍歷1到n的每乙個數,計算其出現1的整數的個數 雖然笨,但是想不出其他方法就這樣了 解法二 分類討論,分別討論個位,十位和百位.上1能出現的次數。假設這個數為abcd,則 d 為1時,出現1...
程式設計之美 1的數目
問題1描述 求1 n十進位制中1的數目f,f 12 5 include typedef long long ll ll sum1s ll n ifactor 10 return icount int main 2 求滿足f n n的最大數 找規律 9以下 1個 99以下 20個 999以下 300個...