程式設計之美 第二章 數字之魅 2 4 1的數目

2021-07-04 06:30:46 字數 3461 閱讀 1567

/*

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的個數,比如f(12) = 5,

2滿足條件f(n) = n的最大n是多少?

劍指解法:

需要用遞迴,拆分成三部分:最高位是1 + 除最高位剩餘的位數的1 + 遞迴的1

最高位不是1

解法1:

從1開始遍歷到n,將其中的每乙個數含有1的個數加起來,

解法2:

給定n,分析小於n的數在每一位上可能出現1的次數之和來得到這個結果,對於乙個特定的n,分析其中規律:

先看1位數的情況:

如果n=3,那麼從1到3的數字是:1,2,3,只有個位數字上可能出現1,而且只出現1次,進一步可以發現如果n是個位數,且n>=1,那麼f(n)都等於1

規律:如果n是個位數,且n>=1,f(n) = 1,如果n=0,f(0) = 0

再看兩位數的情況:

如果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恰好被計算了兩次。

n=23,十位出現1的次數為10次,從10~19,個位出現1的次數為1,11,21,所以f(23) = 10 + 3 = 13

個位數出現1的次數不僅和個位數字有關,還和10位數字有關;如果n的個位數》=1,則個位出現1的次數為十位數的數字加1

= 0,則個位出現1的次數為十位數的數字

十位數=1,則十位數上出現1的次數為個位數的數字加1

十位數》1,則十位數上出現1的次數為10

分析3位數:

n=123

個位出現1的個數為13:1,11,21,...,91,101,111,121

十位出現1的個數為20:10~19,110~119

百位出現1的個數為24:100~23

假設n=abcde,這裡a,b,c,d,e分別是十進位制數n的各個數字上的數字。如果要計算百位上出現1的次數,它收到3個因素的影響,百位上的數字,百位以下,百位以上

如果百位 = 0,百位上出現1的次數由更高位決定:比如12013,百位出現1的情況可能是100~199,1100~1199,2100~2199,。。。,11100~11199,一共有1200個

由更高位的數字12*當前位數100

如果百位上的數字為1,百位出現1的次數不僅受更高位影響,還受低位影響,比如12113,受更高位影響,百位出現1的情況時100~199,1100~1199,2100~2199,。。。,

11100~11199,gong 1200個,等於更高位數字12*當前位數。

受低位影響,百位出現1的情況時12100~12113,等於低位數字113+1

如果百位上數字大於1(即為2~9),則百位上出現1的次數僅由更高位決定,比如12213,則百位上出現1的可能性為:100~199,1100~1199,2100~2199,...,11100~11199,

12100~12199共1300個。=更高位數字加1*當前位數= (12+1)*100

問題2的解法:

要確定最大的數n,滿足f(n) = n,分析

9以下為:1個

99以下為:10*1 + 10*1 = 20

999以下為:(99+1)*1 + (9+1)*10 + (0+1)*100 = 100 + 100 + 100 = 300

9999以下為:(0+1)*1000+10*300 = 4000

999 999 999 以下為:900 000 000個

9 999 999 999 以下為:10 000 000 000個

歸納得:f(10^n-1) = n*10^(n-1)

當n>10^10 - 1,f(n)的值大於n,可以猜想,當n大於某乙個數n時,f(n)會始終比n大,也就是說最大滿足條件在0~n之間,如果能估計出這個n,只要讓n從n往0遞減,

第乙個滿足的的數就是要求的整數

問題轉化為如何證明上界n存在,並估計該上界n。

令n=10^11-1=99 999 999 999,讓n從n往0遞減,依次檢查是否有f(n) = n,第乙個滿足條件的就是我們要找的整數。得出n = 1 111 111 110,是滿足f(n) =n的最大整數

輸入:2

1223

123輸出:15

1357

*//*

關鍵:1 llow = n - (n/lfactor)*lfactor;//參見123 - (123/10)*10

lcur = (n / lfactor) % 10;//參見(123/10)%10

lhigh = n / (lfactor * 10);//參見123 / (10*10)

2 case 0: lcount += lhigh * lfactor;//如果當前位為0,那麼當前位出現1的次數 = 高位*位數

break;

case 1: lcount += lhigh * lfactor + llow + 1;//如果當前位為1,那麼當前位出現1的次數 = 高位 * 位數 + 低位 + 1

break;

default: lcount += (lhigh + 1) * lfactor;//如果當前位》=2,那麼當前為出現1的次數 = (高位+1)*位數

3 當n>10^10 - 1,f(n)的值大於n,可以猜想,當n大於某乙個數n時,f(n)會始終比n大,也就是說最大滿足條件在0~n之間,如果能估計出這個n,只要讓n從n往0遞減,

第乙個滿足的的數就是要求的整數

問題轉化為如何證明上界n存在,並估計該上界n。

令n=10^11-1=99 999 999 999,讓n從n往0遞減,依次檢查是否有f(n) = n,第乙個滿足條件的就是我們要找的整數。得出n = 1 111 111 110,是滿足f(n) =n的最大整數

long long ln = 1e11 - 1;

*/#include int count1(int n)

while(n);

return iret;

}long long count1_divide(int n)

lfactor *= 10;

} return lcount;

}long long findn()

ln--; }

}void process()

//printf("%d\n",iret);

printf("%lld\n",count1_divide(n)); }}

void process2()

int main(int argc,char* argv)

程式設計之美 第二章 數字之魅 2 3尋找發帖水王

尋找發帖水王 本質 尋找出現超過一半次數的人 如果已經排序,那麼中序數就是那個人,即下標是,這個列表的第n 2項是 從0開始編號 如果每次刪除兩個不同的id,可以降低時間複雜度 輸入 7 1 2 3 2 4 2 2 81 2 3 2 4 2 2 5 輸出 2 沒有 include const int...

程式設計之美 第二章 數字之魅 2 5尋找最大的k個數

尋找最大的k個數 解法1 如何避免對後n k個數的排序,選擇排序和交換排序都是不錯的選擇,o n k 如果k log2n時,那麼可以選擇部分排序。解法三 尋找n個數中最大的k個數,本質就是尋找最大的k個數中最小的那個,也就是第k大的數。可以使用二分搜尋,對於乙個給定的數p,可以在o n 的時間複雜度...

第二章 程式設計之道

程式設計師的修煉從優秀帶卓越 第二章 程式設計之道 切記一根筋 優秀的開發者和平庸的開發者之間存在著的一條鴻溝,因為優秀的程式設計師所具有的的素質似乎是與生俱來。那麼成為優秀的程式設計師的方法是拋開程式設計,放下編譯器,好好的評估一下自己正在做的事情。你必須培養自己對於程式設計周邊所有事情的熱情。你...