1. 程式人生 > >LintCode統計數字:計算數字k在0到n中的出現的次數,k可能是0~9的一個值

LintCode統計數字:計算數字k在0到n中的出現的次數,k可能是0~9的一個值

現在是2018-9-21,距離畢業還有不到兩年的時間,情況樂觀的話,我應該會在一年之內去找一份實習工作。對於找工作這件事,此刻的我還是有些惶恐,我無法確定清晰的職業方向和目標,對自己的知識儲備也不自信。為了給即將面對的求職做些準備,我覺得有必要提升自己的演算法設計能力。讀研以前也接觸過演算法競賽,但是淺嘗輒止。現在我決定重新關注演算法,從這裡踏上正式學習演算法的第一步。

第一題!

題目描述:

題目出處:

解析:

部落格 求1~n中0~9出現的次數給出了暴力破解和數字規律兩種解法,很多文章都歸納了題目中的數字規律,本文通過閱讀解法二程式碼來理解規律。

假設num=123,target=1。

第一次迴圈

首先考慮個位數為1的數字個數

此時base=1,n=123,cur=3,sum=0

當數字個位數為1時,高位數(本例中的百位和十位數)最大隻能取12,當高位數取最大值12時,必須知道target和num個位數數字(cur)的大小關係才能確定滿足條件的數字個數。如果高位數<12(0~11),則無需考慮target和cur的大小關係就能確定滿足條件的數字個數,因為此時無論num個位數和cur的大小關係如何,數字都小於123。高位數小於12的情況共有12(n/10)種情況,即{0~11},這正是base*(n/10)代表的意義。

程式碼先考慮高位數<12的情況下,滿足條件的數字個數共有:

sum+=base*(n/10)#sum+=12

然後再分類討論高位數=12時的情況,此時target和cur的大小,可能存在3種情況:target<cur target=cur target>cur,三種情況對結果的影響稍有不同。

拿此例來說,因為1<3,所以個位數字為1的數字除了上面的集合之外,還有121。

sum+=1*base#sum+=1

但如果target不等於1而是大於3,那麼在120~123這個數字範圍內,不存在個位數為target的數字。

(base的意義和target剛好等於cur的情況留在下一次迴圈中討論)

第二次迴圈

總結有哪些數字十位數為1

base=10,num=12,cur=2

同理,此時高位數(本例中的百位數)最大隻能取1,先考慮百位數小於1的情況,共有1(n/10)種,即0.

百位數取0,無需考慮cur和target的大小關係,保證十位數為1且合法的數字有{10,11,……,19}。因為target處在十位上,所以滿足條件的數字個位數共有0~9共10種取值可能,這也是在處理十位數時,base=10的原因。如果target處在千位上,那base將等於100,以此類推。

sum+=base*(n/10)#sum+=10

當百位數為1 時,十位數最大不能超過2(如果十位數等於2,符合要求的數字還有{120,121,122,123},共num%base+1種情況,處理百位數字為1的時候,base將等於100)

本例中要求十位數字為1,因為1<2,滿足要求的數字除了上述的{10,11,……,19}外,還有{110~119},共base種可能。

sum+=base#sum+=10

第二次迴圈結束後,n=1,base=100,cur=1。

第三次迴圈

此時,n/10=0,高位數最大能取值0,高位數不能取小於0的數,所以

sum+=base*(n/10)#sum+=0

當高位數取0的時候,再次比較cur和target的大小,因為1=1,所以

sum+=num%base+1#sum+=24

這24個數是{100~123}

至此,1在0~123中出現的次數求解完畢。

特殊情況K=0

當k為1~9時,都可以用這種方式來求解,k取0時,需特殊考慮。

K=0和其他情況的區別在於,target高位的最小值是1而不是0,所以

sum+=base*(n/10)修改為sum+=base*(n/10-1)

此外,K一定小於等於當前位數上的值,所以無需判斷K是否大於cur。

詳細的解釋和程式碼請參見原文

重複計數

我在懷疑這樣會不會造成重複計數,答案是不會。觀察num=12,K=1的計算結果,就發現演算法並沒有重複計數。對於11來說,原因在於個位取1和十位取1分別都對11記了一次數,11有兩個1,本身也需要兩次計數。

(先不考慮1和num個位數數字(cur=3)的大小關係,個位的高位共有(n/10)種取值可能保證個位數為1的數字在0~123之間,它們是{1,11,21,31,……,111},共有12個,這正是base*(n/10)代表的意義。(如果取高位為12,因為無法確定target和cur的大小,也將無法確定此時滿足條件的數字個數,後面會對這種情況分類討論)

(同樣,先不考慮target和num十位數數字的大小關係,十位的高位只能取0才能保證十位數為1的數字合法,這樣的數字有{10,11,……,19},因為target處在十位上,所以滿足條件的數字個位數共有0~9共10種取值可能,這也是在處理十位數時,base=10的原因。如果target處在千位上,那base將等於100,以此類推。)