1的數目 程式設計之美

2021-07-22 02:30:06 字數 2766 閱讀 6960

給定乙個十進位制正整數 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個...