Skip to content

Commit 19a6361

Browse files
committed
digit dp
1 parent 324d5eb commit 19a6361

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed

3490. Count Beautiful Numbers.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""
2+
https://leetcode.com/problems/count-beautiful-numbers/description/
3+
Count numbers in [l,r] where product of digits is divisible by the sum
4+
6D Digit DP, try each possible sum and product
5+
Possible sums: 9*9 = 81
6+
Possible products: not sure, apparently not that much
7+
8+
Note: we need an extra state that represents whether we are still doing
9+
leading zeros as those don't contribute to the product
10+
11+
Not sure why is this faster than trying all sums independently and doing product (mod sum)
12+
This would technically result in only 81^2 possible `product` values
13+
"""
14+
15+
16+
def beautifulNumbers(l: int, r: int) -> int:
17+
n = max(len(str(l)), len(str(r)))
18+
sl = list(map(int, str(l).zfill(n)))
19+
sr = list(map(int, str(r).zfill(n)))
20+
21+
cache = {}
22+
23+
def solve(touch_l, touch_r, idx, added, product, zeros):
24+
if idx == n: # fully constructed number state
25+
return product % added == 0
26+
27+
state = (touch_l, touch_r, idx, added, product, zeros) # cache
28+
if state in cache:
29+
return cache[state]
30+
31+
total = 0
32+
33+
low = sl[idx] if touch_l else 0
34+
high = sr[idx] if touch_r else 9
35+
for d in range(low, high + 1):
36+
new_zeros = zeros and d == 0 # check if still leading zeros
37+
total += solve(touch_l and d == sl[idx],
38+
touch_r and d == sr[idx],
39+
idx + 1,
40+
added + d,
41+
1 if new_zeros else product * d,
42+
new_zeros)
43+
44+
cache[state] = total
45+
return cache[state]
46+
47+
return solve(True, True, 0, 0, 1, True)
48+
49+
50+
print(beautifulNumbers(20, 100))
51+
print(beautifulNumbers(10, 20))
52+
print(beautifulNumbers(1, 15))
53+
54+
55+
# alternate solution that TLEs, fixes the target sum beforehand and tries all possible
56+
class Solution:
57+
def beautifulNumbers(self, l: int, r: int) -> int:
58+
n = max(len(str(l)), len(str(r)))
59+
sl = list(map(int, str(l).zfill(n)))
60+
sr = list(map(int, str(r).zfill(n)))
61+
62+
def solve(touch_l, touch_r, idx, added, product, zeros):
63+
if added > target: # went over
64+
return 0
65+
if idx == n: # fully constructed number state
66+
return product == 0 and added == target
67+
68+
state = (touch_l, touch_r, idx, added, product, zeros) # cache
69+
if state in cache:
70+
return cache[state]
71+
72+
total = 0
73+
74+
low = sl[idx] if touch_l else 0
75+
high = sr[idx] if touch_r else 9
76+
for d in range(low, high + 1):
77+
new_zeros = zeros and d == 0
78+
total += solve(touch_l and d == sl[idx],
79+
touch_r and d == sr[idx],
80+
idx + 1,
81+
added + d,
82+
1 if new_zeros else product * d % target,
83+
new_zeros)
84+
85+
cache[state] = total
86+
return cache[state]
87+
88+
total = 0
89+
for target in range(1, 9 * n + 1):
90+
cache = {}
91+
total += solve(True, True, 0, 0, 1, True)
92+
return total

0 commit comments

Comments
 (0)