數位枚舉 - 求2的出現次數

這是讀書時一篇舊文搬運.幾年後再次回顧下算法.

問題

給定一個數字n,求1到n序列中2出現的總次數。n最大值可能是10^9。

思路

暴力

依次求解1..n每個數含有多少個2,最後求和。

給定數字n,其位數(10進制)為logn,具體的時間復雜度大致如下:

T(n) = log_{10}n + log_{10}{(n-1)} + ... + log_{10}{1} = log_{10}{n!} = O(log_{10}{n!}) Rightarrow T(n) = O(log{n^n}) = O(nlogn)

所以,暴力法時間復雜度是nlogn

數位枚舉

換一個枚舉思路,正常的枚舉是 i -> i+1 -> i+2 ...這樣,

現采用數位遍歷的方式,假設n是K位數,所有出現的2,出現的位置隻能在這個范圍內:[0,K-1]。(從0開始比較好算)

所以問題可以轉變為:對於每個 din[0,K-1] ,求符合條件為 in[1,n] 且第d位為2的數字的個數和 S_d ,最後累加 sum_{d=1}^KS_d

關鍵點在於對於第d位為2的數字個數如何求解?

很容易我們可以歸納出數字個數與第d位數字與2的大小關系有關:

PS: 以下的d是從0開始取的。

  • 給定n,假設第d位數字小於2,舉個例子:

n = 716130, d = 2, 第d位數字為1,該位為2且滿足小於等於n的數字是:

200 - 2991200 - 12992200 - 2299, ..., 715200 - 715299,顯然有716 * 100

規約下,有:

S_d = n / 10^{d+1} * 10^d qquad text{if} digit(d,n) lt2

  • 類似地,假設第d位數字大於2,舉個例子:

n = 716130, d = 3, 第d位數字為6,該位為2且滿足小於等於n的數字是:

2000 - 299912000-12999,...,712000-712999,顯然有72*1000個,

規約下,有:

S_d = (n / 10^{d+1}+1) * 10^d qquad text{if} digit(d,n) gt2

  • 最後一種可能,假設第d位數字等於2,舉個例子:

n = 716230, d = 2,第d位數字為2,該位為2且滿足小於等於n的數字應該就是第d位小於2的情況下的 S_d 再加上餘出來的716200 - 716230這31個數字

規約下,有:

S_d = n / 10^{d+1} * 10^d + (n - (n mod 10^{d}) + 1) qquad text{if} digit(d,n) = 2

最後遍歷n的每一位,求出這些數字在累加即可。

新算法的復雜度隻與位數相關,也就是O(logn)

總結下來,難點在於如何轉變為數位枚舉的思維方式,即把一般直覺上的子問題:給定一個數字,求這個數字含有的2的個數,轉為,求2在這些數字裡的第d位一共出現瞭幾次==>轉為數符合這樣的數的個數問題。 另外對於某個數字含有多個2而言(如202),其實是被枚舉過程計算多次的,從而符合2的總個數要求。

0 1 ... 9
10 11 ... 19
20 21 ... 29

发表回复

相关推荐

青年干部要学会俯下身子

青年强则国家强,青年干部作为青年中的佼佼者,不仅要在在永葆青春向上的同时,更要沉下心来、俯下身子投身基层,在“接地气” ...

· 26分钟前

宝宝奇葩睡姿大赏!练瑜伽、会劈叉、还有杂技?宝妈看了都想笑

都说生活就像一盘巧克力,你永远不知道下一颗是什么味道。

· 26分钟前

手機充電慢?原來跟這些事有關

網上流傳瞭一個快速充電的小竅門,說是手機關機充電或者切換飛行模式充電,速度能夠快一倍。可是即便沒有這個小竅門,這些年...

· 26分钟前

天文史上的今天:哥白尼诞辰

摘要: 1473年2月19日,哥白尼诞辰。 他提出了“日心说”,奠定了现代天文学的基础。 哥白尼(1473年2月19日~1543年5月24日) ...

· 26分钟前

在家里就能赚钱的工作,月入过万不是梦!

在家工作是现代社会的一个趋势,尤其是在新冠疫情期间,越来越多的人选择在家里工作。然而,很多人不知道在家里可以做哪些工 ...

· 26分钟前

Copyright 2015-2025 www.icpchaxun.com ©All Rights Reserved.