Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit ce5147d

Browse files
feat: add solutions to lc problem: No.0902 (doocs#3544)
No.0902.Numbers At Most N Given Digit Set
1 parent da3ed3d commit ce5147d

File tree

7 files changed

+401
-347
lines changed

7 files changed

+401
-347
lines changed

‎solution/0900-0999/0902.Numbers At Most N Given Digit Set/README.md‎

Lines changed: 137 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -90,18 +90,25 @@ $$
9090

9191
基本步骤如下:
9292

93-
1. 将数字 $n$ 转为 int 数组 $a,ドル其中 $a[1]$ 为最低位,而 $a[len]$ 为最高位;
94-
1. 根据题目信息,设计函数 $dfs(),ドル对于本题,我们定义 $dfs(pos, lead, limit),ドル答案为 $dfs(len, 1, true)$。
93+
我们将数字 $n$ 转化为字符串 $s,ドル记字符串 $s$ 的长度为 $m$。
9594

96-
其中:
95+
接下来,我们设计一个函数 $\textit{dfs}(i, \textit{lead}, \textit{limit}),ドル表示当前处理到字符串的第 $i$ 位,到最后一位的方案数。其中:
9796

98-
- `pos` 表示数字的位数,从末位或者第一位开始,一般根据题目的数字构造性质来选择顺序。对于本题,我们选择从高位开始,因此,`pos` 的初始值为 `len`;
99-
- `lead` 表示当前数字中是否包含前导零,如果包含,则为 `1`,否则为 `0`;初始化为 `1`;
100-
- `limit` 表示可填的数字的限制,如果无限制,那么可以选择 $[0,1,..9],ドル否则,只能选择 $[0,..a[pos]]$。如果 `limit``true` 且已经取到了能取到的最大值,那么下一个 `limit` 同样为 `true`;如果 `limit``true` 但是还没有取到最大值,或者 `limit``false`,那么下一个 `limit``false`
97+
- 数字 $i$ 表示当前处理到字符串 $s$ 的第 $i$ 位;
98+
- 布尔值 $\textit{lead}$ 表示是否只包含前导零;
99+
- 布尔值 $\textit{limit}$ 表示当前位置是否受到上界的限制
101100

102-
关于函数的实现细节,可以参考下面的代码。
101+
函数的执行过程如下:
103102

104-
时间复杂度 $O(\log n)$。
103+
如果 $i$ 大于等于 $m,ドル说明我们已经处理完了所有的位数,此时如果 $\textit{lead}$ 为真,说明当前的数字是前导零,我们应当返回 0ドル$;否则,我们应当返回 1ドル$。
104+
105+
否则,我们计算当前位置的上界 $\textit{up},ドル如果 $\textit{limit}$ 为真,则 $up$ 为 $s[i]$ 对应的数字,否则 $up$ 为 9ドル$。
106+
107+
然后,我们在 $[0, \textit{up}]$ 的范围内枚举当前位置的数字 $j,ドル如果 $j$ 为 0ドル$ 且 $\textit{lead}$ 为真,我们递归计算 $\textit{dfs}(i + 1, \text{true}, \textit{limit} \wedge j = \textit{up})$;否则,如果 $j$ 在 $\textit{digits}$ 中,我们递归计算 $\textit{dfs}(i + 1, \text{false}, \textit{limit} \wedge j = \textit{up})$。累加所有的结果即为答案。
108+
109+
最后,我们返回 $\textit{dfs}(0, \text{true}, \text{true})$ 即可。
110+
111+
时间复杂度 $O(\log n \times D),ドル空间复杂度 $O(\log n)$。其中 $D = 10$。
105112

106113
相似题目:
107114

@@ -120,69 +127,59 @@ $$
120127
class Solution:
121128
def atMostNGivenDigitSet(self, digits: List[str], n: int) -> int:
122129
@cache
123-
def dfs(pos, lead, limit):
124-
if pos <= 0:
125-
return lead == False
126-
up = a[pos] if limit else 9
130+
def dfs(i: int, lead: int, limit: bool) -> int:
131+
if i >= len(s):
132+
return lead ^ 1
133+
134+
up = int(s[i]) if limit else 9
127135
ans = 0
128-
for i in range(up + 1):
129-
if i == 0 and lead:
130-
ans += dfs(pos - 1, lead, limit and i == up)
131-
elif i in s:
132-
ans += dfs(pos - 1, False, limit and i == up)
136+
for j in range(up + 1):
137+
if j == 0 and lead:
138+
ans += dfs(i + 1, 1, limit and j == up)
139+
elif j in nums:
140+
ans += dfs(i + 1, 0, limit and j == up)
133141
return ans
134142

135-
l = 0
136-
a = [0] * 12
137-
s = {int(d) for d in digits}
138-
while n:
139-
l += 1
140-
a[l] = n % 10
141-
n //= 10
142-
return dfs(l, True, True)
143+
s = str(n)
144+
nums = {int(x) for x in digits}
145+
return dfs(0, 1, True)
143146
```
144147

145148
#### Java
146149

147150
```java
148151
class Solution {
149-
private int[] a = new int[12];
150-
private int[][] dp =newint[12][2];
151-
private Set<Integer> s =newHashSet<>();
152+
private Set<Integer> nums = new HashSet<>();
153+
private char[] s;
154+
private Integer[] f;
152155

153156
public int atMostNGivenDigitSet(String[] digits, int n) {
154-
for (var e : dp) {
155-
Arrays.fill(e, -1);
157+
s = String.valueOf(n).toCharArray();
158+
f = new Integer[s.length];
159+
for (var x : digits) {
160+
nums.add(Integer.parseInt(x));
156161
}
157-
for (String d : digits) {
158-
s.add(Integer.parseInt(d));
159-
}
160-
int len = 0;
161-
while (n > 0) {
162-
a[++len] = n % 10;
163-
n /= 10;
164-
}
165-
return dfs(len, 1, true);
162+
return dfs(0, true, true);
166163
}
167164

168-
private int dfs(int pos, int lead, boolean limit) {
169-
if (pos <=0) {
170-
return lead ^ 1;
165+
private int dfs(int i, boolean lead, boolean limit) {
166+
if (i >= s.length) {
167+
return lead ?0: 1;
171168
}
172-
if (!limit && lead !=1&& dp[pos][lead] != -1) {
173-
return dp[pos][lead];
169+
if (!lead && !limit && f[i] != null) {
170+
return f[i];
174171
}
172+
int up = limit ? s[i] - '0' : 9;
175173
int ans = 0;
176-
int up = limit ? a[pos] : 9;
177-
for (int i = 0; i <= up; ++i) {
178-
if (i == 0 && lead == 1) {
179-
ans += dfs(pos - 1, lead, limit && i == up);
180-
} else if (s.contains(i)) {
181-
ans += dfs(pos - 1, 0, limit && i == up);
174+
for (int j = 0; j <= up; ++j) {
175+
if (j == 0 && lead) {
176+
ans += dfs(i + 1, true, limit && j == up);
177+
} else if (nums.contains(j)) {
178+
ans += dfs(i + 1, false, limit && j == up);
182179
}
183180
}
184-
if (!limit && lead ==0) {
185-
dp[pos][lead] = ans;
181+
if (!lead && !limit) {
182+
f[i] = ans;
186183
}
187184
return ans;
188185
}
@@ -194,43 +191,37 @@ class Solution {
194191
```cpp
195192
class Solution {
196193
public:
197-
int a[12];
198-
int dp[12][2];
199-
unordered_set<int> s;
200-
201194
int atMostNGivenDigitSet(vector<string>& digits, int n) {
202-
memset(dp, -1, sizeof dp);
203-
for (auto& d : digits) {
204-
s.insert(stoi(d));
205-
}
206-
int len = 0;
207-
while (n) {
208-
a[++len] = n % 10;
209-
n /= 10;
195+
string s = to_string(n);
196+
unordered_set<int> nums;
197+
for (auto& x : digits) {
198+
nums.insert(stoi(x));
210199
}
211-
return dfs(len, 1, true);
212-
}
213-
214-
int dfs(int pos, int lead, bool limit) {
215-
if (pos <= 0) {
216-
return lead ^ 1;
217-
}
218-
if (!limit && !lead && dp[pos][lead] != -1) {
219-
return dp[pos][lead];
220-
}
221-
int ans = 0;
222-
int up = limit ? a[pos] : 9;
223-
for (int i = 0; i <= up; ++i) {
224-
if (i == 0 && lead) {
225-
ans += dfs(pos - 1, lead, limit && i == up);
226-
} else if (s.count(i)) {
227-
ans += dfs(pos - 1, 0, limit && i == up);
200+
int m = s.size();
201+
int f[m];
202+
memset(f, -1, sizeof(f));
203+
auto dfs = [&](auto&& dfs, int i, bool lead, bool limit) -> int {
204+
if (i >= m) {
205+
return lead ? 0 : 1;
228206
}
229-
}
230-
if (!limit && !lead) {
231-
dp[pos][lead] = ans;
232-
}
233-
return ans;
207+
if (!lead && !limit && f[i] != -1) {
208+
return f[i];
209+
}
210+
int up = limit ? s[i] - '0' : 9;
211+
int ans = 0;
212+
for (int j = 0; j <= up; ++j) {
213+
if (j == 0 && lead) {
214+
ans += dfs(dfs, i + 1, true, limit && j == up);
215+
} else if (nums.count(j)) {
216+
ans += dfs(dfs, i + 1, false, limit && j == up);
217+
}
218+
}
219+
if (!lead && !limit) {
220+
f[i] = ans;
221+
}
222+
return ans;
223+
};
224+
return dfs(dfs, 0, true, true);
234225
}
235226
};
236227
```
@@ -239,48 +230,79 @@ public:
239230
240231
```go
241232
func atMostNGivenDigitSet(digits []string, n int) int {
242-
s := map[int]bool{}
243-
for _, d := range digits {
244-
i, _ := strconv.Atoi(d)
245-
s[i] = true
233+
s := strconv.Itoa(n)
234+
m := len(s)
235+
f := make([]int, m)
236+
for i := range f {
237+
f[i] = -1
246238
}
247-
a := make([]int, 12)
248-
dp := make([][2]int, 12)
249-
for i := range a {
250-
dp[i] = [2]int{-1, -1}
251-
}
252-
l := 0
253-
for n > 0 {
254-
l++
255-
a[l] = n % 10
256-
n /= 10
239+
nums := map[int]bool{}
240+
for _, d := range digits {
241+
x, _ := strconv.Atoi(d)
242+
nums[x] = true
257243
}
258-
var dfs func(int, int, bool) int
259-
dfs = func(pos, lead int, limit bool) int {
260-
if pos <= 0 {
261-
return lead ^ 1
244+
var dfs func(i int, lead, limit bool) int
245+
dfs = func(i int, lead, limit bool) int {
246+
if i >= m {
247+
if lead {
248+
return 0
249+
}
250+
return 1
262251
}
263-
if !limit && lead == 0&& dp[pos][lead] != -1 {
264-
return dp[pos][lead]
252+
if !lead && !limit && f[i] != -1 {
253+
return f[i]
265254
}
266255
up := 9
267256
if limit {
268-
up = a[pos]
257+
up = int(s[i] - '0')
269258
}
270259
ans := 0
271-
for i := 0; i <= up; i++ {
272-
if i == 0 && lead == 1 {
273-
ans += dfs(pos-1, lead, limit && i == up)
274-
} else if s[i] {
275-
ans += dfs(pos-1, 0, limit && i == up)
260+
for j := 0; j <= up; j++ {
261+
if j == 0 && lead {
262+
ans += dfs(i+1, true, limit && j == up)
263+
} else if nums[j] {
264+
ans += dfs(i+1, false, limit && j == up)
276265
}
277266
}
278-
if !limit {
279-
dp[pos][lead] = ans
267+
if !lead && !limit {
268+
f[i] = ans
280269
}
281270
return ans
282271
}
283-
return dfs(l, 1, true)
272+
return dfs(0, true, true)
273+
}
274+
```
275+
276+
#### TypeScript
277+
278+
```ts
279+
function atMostNGivenDigitSet(digits: string[], n: number): number {
280+
const s = n.toString();
281+
const m = s.length;
282+
const f: number[] = Array(m).fill(-1);
283+
const nums = new Set<number>(digits.map(d => parseInt(d)));
284+
const dfs = (i: number, lead: boolean, limit: boolean): number => {
285+
if (i >= m) {
286+
return lead ? 0 : 1;
287+
}
288+
if (!lead && !limit && f[i] !== -1) {
289+
return f[i];
290+
}
291+
const up = limit ? +s[i] : 9;
292+
let ans = 0;
293+
for (let j = 0; j <= up; ++j) {
294+
if (!j && lead) {
295+
ans += dfs(i + 1, true, limit && j === up);
296+
} else if (nums.has(j)) {
297+
ans += dfs(i + 1, false, limit && j === up);
298+
}
299+
}
300+
if (!lead && !limit) {
301+
f[i] = ans;
302+
}
303+
return ans;
304+
};
305+
return dfs(0, true, true);
284306
}
285307
```
286308

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /