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
120127class 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
148151class Solution {
149- private int [] a = new int [ 12 ] ;
150- private int [][] dp = new int [ 12 ][ 2 ] ;
151- private Set< Integer > s = new HashSet<> () ;
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
195192class Solution {
196193public:
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
241232func 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