編寫乙個方法,計算從 0 到 n (含 n) 中數字 2 出現的次數。
示例:輸入:
25輸出:
9解釋:(2
,12,20
,21,22
,23,24
,25)(注意 22 應該算作兩次)
n <=10^
9
一、dp方法
第i位是1:
dp[3] = 當第3位是0,1-2位取00-99時2的次數 + 當第3位是1, 1-2位取00~78時2的次數
dp[3] = numberof2sinrange(99) + dp[2]
numberof2sinrange(178) = numberof2sinrange(99) + numberof2sinrange(78)
第i位是2:
dp[3] = 第3位取0-1,1-2位取00-99時2的次數 + 第3位是2,1-2位取00-33時2在1-2位出現的次數 + 第3位是2,1-2位取00~33時2在第3位出現的次數
dp[3] = 2 *numberof2sinrange(99) + dp[2] + 33 + 1
numberof2sinrange(233) = 2 * numberof2sinrange(99) + numberof2sinrange(33) + 33 + 1
第i位大於2:
dp[3] = 第3位取0-3,1-2位取00-99時2出現在1-2位的次數 + 第3位取4,1-2位取00-78時2的次數 + 第3位取2,1-2位取00-99時2出現在第3位的次數
dp[3] = 4 * numberof2sinrange(99) + dp[2] + 100
總結:dp[i]與dp[i-1]的關係,假設n的第i位的值為k
dp[i] = k * numberof2sinrange(99…9) + dp[i-1] + +
class
solution
:def
numberof2sinrange
(self, n:
int)
->
int:
if n ==0:
return
0 digit =
int(math.log(n))+
1 dp =[[
0,0]
for _ in
range
(digit +1)
]#dp[i][0] = numberof2sinrange(n % pow(10, i)) 儲存0~n的1-i位組成的數包含2的個數
#dp[i][1] = numberof2sinrange(99..9) 儲存i位均為9包含2的個數
dp[1]
[0]=
1if n %
10>=
2else
0 dp[1]
[1]=
1for i in
range(2
,digit+1)
: k = n //
(int
(math.
pow(
10, i-1)
))%10
dp[i][0
]= k * dp[i-1]
[1]+ dp[i-1]
[0]if k ==2:
dp[i][0
]+= n %
(int
(math.
pow(
10, i-1)
))+1
elif k >2:
dp[i][0
]+=int(math.
pow(
10, i-1)
) dp[i][1
]=10* dp[i-1]
[1]+
int(math.
pow(
10, i-1)
)return dp[digit][0
]
二、切片法
分別統計每位(個、十、百、千位等等)出現2的次數:
百位大於2(12313):
要想百位出現2,由於當前百位是3,那麼最終的次數只依賴於更高位
00200-00299 100個數
01200-01299 100個數
…12200-12299 100個數
所有百位出現2的總個數為從0到12 共13個100,即13*100=1300
百位小於2(12113):
要想百位出現2,由於當前位是1,那麼最終的次數同樣依賴於更高位,只不過會比上面的情況少最後一種
00200-00299 100個數
01200-01299 100個數
…11200-11299 100個數
那麼加起來就是(12)10**len(『13』)
百位2等於2(12213):
首先我們取前三位不大於121的所有情況,就是上面的結論2
00200-00299 100個數
01200-01299 100個數
…11200-11299 100個數,還是12100個數,其次取前三位是122的情況:
12200-12213 這一共是14個數。
class
solution
:def
numberof2sinrange
(self, n:
int)
->
int:
s =str(n)
cnt =
0for i in
range
(len
(s))
: current =
int(s[i]
) high =
0if s[
:i]==
''else
int(s[
:i])
low =
0if s[i+1:
]==''else
int(s[i+1:
])if current >2:
cnt +=
(high +1)
*(10**
len(s[i+1:
]))elif current <2:
cnt +=
(high)*(
10**
len(s[i+1:
]))else
: cnt +=
(high)*(
10**
len(s[i+1:
]))+ low +
1return cnt
使用數學方法表達時:
給定數字從個位開始向上分析
例如n=324時
i a b res
1 324 0 (324+7)/101 + 0 = 33
10 32 4 (32+7)/1010 + 5 = 35
100 3 24 (3+7)/10*100 = 100
「+7」是為特殊情況設計,當取值為0,1,2時不會產生進製,大於2時允許產生進製。
class
solution
:def
numberof2sinrange
(self, n:
int)
->
int:
if n <=1:
return
0if n <=11:
return
1 a, b, res =0,
0,0 i =
1while i <= n:
a = n//i
b = n%i
res +=
(a +7)
//10
*i +
(a%10==2
)*(b+1
) i *=
10return res
整數中1出現的次數
針對牛客網試題作個記錄 問題 整數中1出現的次數 從1到n整數中1出現的次數 求出1 13的整數中1出現的次數,並算出100 1300的整數中1出現的次數?為此他特別數了一下1 13中包含1的數字有1 10 11 12 13因此共出現6次,但是對於後面問題他就沒轍了。acmer希望你們幫幫他,並把問...
整數中1出現的次數
乙個更好的辦法是利用數學公式直接計算出最終的結果,該方法是依次求出數字 x 在個位 十位 百位等等出現的次數,再相加得到最終結果。這裡的 x 1,9 x 1,9 因為 x 0 x 0不符合下列規律,需要單獨計算。首先要知道以下的規律 依此類推,從 1 至 10 i 10i 在它們的左數第二位 右數第...
整數中1出現的次數
題目 求出1 13的整數中1出現的次數,並算出100 1300的整數中1出現的次數?為此他特別數了一下1 13中包含1的數字有1 10 11 12 13因此共出現6次,但是對於後面問題他就沒轍了。acmer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數。從1到n整數...