從1到n整數中1出現的次數 python 實現

2021-10-04 11:46:44 字數 2939 閱讀 6667

輸入乙個正整數n,求從1到n這n個整數的十進位制表示中1出現的次數。例如輸入12,從1到12這些整數中包含1的數字有1,10,11和12。1一共出現了5次。

暴力解法就是從頭到尾說每個數中1的個數,然後求和。數每個數中1的個數需要的複雜度為o(logn),而每個數都需要數一遍,因此總的演算法複雜度為o(nlogn)。

遞迴法就是把數按位對數進行拆分,一步一步縮小數的規模,比如 n=23417 時,可以把問題拆為1–3417和3418–23417,每步先對後一部分進行計算,前一部分可以看成 n=3417 時的求解。這樣就可以先分析下 3418–23417 一共有多少個1呢?首先這些數中包含 10000~19999 這一萬個第乙個數字為1的數。就是先算下和後面乙個數字數相同時第乙個數字為1的數一共多少個。後面乙個數去掉第乙個數字後還有4位,這4為每乙個位上都能為1,當其中一位為1時,其它3位可以是 0-9 這10個數中的任何乙個,因此一共的個數字 4∗3

104*3^

4∗31

0,又由於第乙個數字2,因此3418–23417的1的總個數字2∗4

∗3

102*4*3^

2∗4∗31

0,最高位從1到2後面的數重複兩遍。我在做這一題的時候,前期有點疑惑的時,在排列組合後面4位數時,這個方法沒有考慮重複的情況,假如第一位選了1,第二個數從0-9 10個數都選一遍,然後第二個數選了1時,第乙個數又從 0-9 10個數選了一遍,這就出現了兩次兩個都為1的數,是不是重複計算了?後來仔細想想發現並沒有,因為每個位只計算在他的位上出現1的次數,比如剛才說的出現兩個數都是1的情況,這時當每個位選1時只算了一次,但其實這個數有兩個1,因此後面的再算一次才能把1都統計了,這個問題是統計數字1出現的次數,不是每個數的情況,乙個數中存在幾個1都要加進去

**如下:

def numberof1temp(n):

if 0 < n < 10:

return 1

if n <= 0:

return 0

sum_1 = 0

str_n = str(n)

len_n = len(str_n)

temp = int(str_n[1:])

first_number = int(str_n[0])

numberoffirst = numberof1firstnumber(str_n)

sum_1 += numberoffirst

numberofleft = first_number * (len_n - 1) * 10**(len_n-2)

sum_1 += numberofleft

sum_1 += numberof1temp(temp)

return sum_1

def numberof1firstnumber(str_n):

first_number = int(str_n[0])

if first_number > 1:

number = 10**(len(str_n)-1)

else:

number = int(str_n[1:]) + 1

return number

通過分析,可以發現:

1到10,個位數是1的個數是:1

1到100,十位數是1的個數是:10

1到1000,百位數是1的個數是:100

因此可以通過看這些數包含幾個10,幾個100,幾個1000來計算1出現的次數。還以23417為例,從1到23417要包括多少個10?數數時:1, 2,3, 4, 5, 6, 7, 8, 9,10,然後1,2, 3, 4, 5, 6, 7, 8, 9, 20,再數 1,2, 3, 4, 5, 6, 7, 8, 9, 30。可以看出除了十位數發生了變化,只是相當於個位數重複了一遍。在數數時,大家也經常隻數個位數,從1到10數一遍記一下,這樣方便好數。十位數同理。23417÷10

=2341

23417\div10=2341

23417÷

10=2

341 那個位數上出現的1的個數就是2341+1

2341+1

2341+1

之所以加1是因為從2341-2347,個位還會再出現乙個1。這個思路從數數隻數個位數,數完一遍記下數,比較好理解。在寫**時,有一點需要注意的是,迴圈時數n的值不應該每次變為n//base,而應該改變base為10*base,因為n//base的餘數是需要留下來計算的,餘數中1出現的次數不能忘了。比如在算十位上1出現的次數時23417

÷100

=234

23417\div100=234

23417÷

100=

234,1出現的次數234∗10

234*10

234∗10

,餘數17十位上1出現的次數也要算進去的,234∗10

234*10

234∗10

只算了 1-23400 中十位上1出現的次數,還有 23401-23417 中十位上1出現的次數。

**如下:

def numberof1(n):

sum_1 = 0

base = 10

while n//(base//10):

m = n // base

b = n % base

if b >= 2 * base//10:

b_sum = base//10

elif b >= 1 * base//10:

b_sum = b % (base//10) + 1

else:

b_sum = 0

sum_1 += m * base//10 + b_sum

base *= 10

return sum_1

在理解演算法時,需要記得計算的是所有數中1出現的次數,也就是後面兩個演算法中分別考慮每個位上1出現的次數。

整數中1出現的次數(從1到n整數中1出現的次數)

求出1 13的整數中1出現的次數,並算出100 1300的整數中1出現的次數?為此他特別數了一下1 13中包含1的數字有1 10 11 12 13因此共出現6次,但是對於後面問題他就沒轍了。acmer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數。include u...

整數中1出現的次數(從1到n整數中1出現的次數)

時間限制 1秒 空間限制 32768k 題目描述 include using namespace std class solution 求之前的length 1位中含乙個數 int base1 0 int base2 1 for int i 0 i1 i cout cout cout 求從base2...

整數中1出現的次數(從1到n整數中1出現的次數)

求出1 13的整數中1出現的次數,並算出100 1300的整數中1出現的次數?為此他特別數了一下1 13中包含1的數字有1 10 11 12 13因此共出現6次,但是對於後面問題他就沒轍了。acmer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數。演算法一 暴力累加...