Skip to content

Commit 2be0589

Browse files
authored
Create count-numbers-with-non-decreasing-digits.py
1 parent fe048b4 commit 2be0589

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Time: O(n^2), n = len(r)
2+
# Space: O(n)
3+
4+
# math, stars and bars, combinatorics
5+
class Solution(object):
6+
def countNumbers(self, l, r, b):
7+
"""
8+
:type l: str
9+
:type r: str
10+
:type b: int
11+
:rtype: int
12+
"""
13+
MOD = 10**9+7
14+
fact, inv, inv_fact = [[1]*2 for _ in xrange(3)]
15+
def nCr(n, k):
16+
while len(inv) <= n: # lazy initialization
17+
fact.append(fact[-1]*len(inv) % MOD)
18+
inv.append(inv[MOD%len(inv)]*(MOD-MOD//len(inv)) % MOD) # https://cp-algorithms.com/algebra/module-inverse.html
19+
inv_fact.append(inv_fact[-1]*inv[-1] % MOD)
20+
return (fact[n]*inv_fact[n-k] % MOD) * inv_fact[k] % MOD
21+
22+
def nHr(n, k):
23+
return nCr(n+k-1, k)
24+
25+
def count(x):
26+
digits_base = []
27+
while x:
28+
x, r = divmod(x, b)
29+
digits_base.append(r)
30+
digits_base.reverse()
31+
if not digits_base:
32+
digits_base.append(0)
33+
result = 0
34+
for i in xrange(len(digits_base)):
35+
if i-1 >= 0 and digits_base[i-1] > digits_base[i]:
36+
break
37+
for j in xrange(digits_base[i-1] if i-1 >= 0 else 0, digits_base[i]):
38+
result = (result + nHr((b-1)-j+1, len(digits_base)-(i+1))) % MOD
39+
else:
40+
result = (result+1)%MOD
41+
return result
42+
43+
return (count(int(r)) - count(int(l)-1)) % MOD
44+
45+
46+
# Time: O(n^2), n = len(r)
47+
# Space: O(n)
48+
# math, stars and bars, combinatorics
49+
class Solution2(object):
50+
def countNumbers(self, l, r, b):
51+
"""
52+
:type l: str
53+
:type r: str
54+
:type b: int
55+
:rtype: int
56+
"""
57+
MOD = 10**9+7
58+
fact, inv, inv_fact = [[1]*2 for _ in xrange(3)]
59+
def nCr(n, k):
60+
while len(inv) <= n: # lazy initialization
61+
fact.append(fact[-1]*len(inv) % MOD)
62+
inv.append(inv[MOD%len(inv)]*(MOD-MOD//len(inv)) % MOD) # https://cp-algorithms.com/algebra/module-inverse.html
63+
inv_fact.append(inv_fact[-1]*inv[-1] % MOD)
64+
return (fact[n]*inv_fact[n-k] % MOD) * inv_fact[k] % MOD
65+
66+
def nHr(n, k):
67+
return nCr(n+k-1, k)
68+
69+
def decrease(digits):
70+
for i in reversed(xrange(len(digits))):
71+
if digits[i]:
72+
digits[i] -= 1
73+
break
74+
digits[i] = 9
75+
76+
def divide(digits, base):
77+
result = []
78+
r = 0
79+
for d in digits:
80+
q, r = divmod(r*10+d, base)
81+
if result or q:
82+
result.append(q)
83+
return result, r
84+
85+
def to_base(digits, base):
86+
result = []
87+
while digits:
88+
digits, r = divide(digits, base)
89+
result.append(r)
90+
result.reverse()
91+
return result
92+
93+
def count(digits):
94+
digits_base = to_base(digits, b)
95+
result = 0
96+
for i in xrange(len(digits_base)):
97+
if i-1 >= 0 and digits_base[i-1] > digits_base[i]:
98+
break
99+
for j in xrange(digits_base[i-1] if i-1 >= 0 else 0, digits_base[i]):
100+
result = (result + nHr((b-1)-j+1, len(digits_base)-(i+1))) % MOD
101+
else:
102+
result = (result+1)%MOD
103+
return result
104+
105+
digits_l = map(int, l)
106+
decrease(digits_l)
107+
digits_r = map(int, r)
108+
return (count(digits_r) - count(digits_l)) % MOD

0 commit comments

Comments
 (0)