25
25
<pre >
26
26
<strong >输入:</strong > n = 5
27
27
<strong >输出:</strong > 5
28
- <strong >解释:</strong >
28
+ <strong >解释:</strong >
29
29
下面列出范围在 [0, 5] 的非负整数与其对应的二进制表示:
30
30
0 : 0
31
31
1 : 1
77
77
78
78
这里我们用记忆化搜索来实现数位 DP。基本步骤如下:
79
79
80
- 1 . 将数字 $n$ 转为二进制字符串 $s$;
81
- 1 . 根据题目信息,设计函数 $\textit{dfs}()$,对于本题,我们定义 $\textit{dfs}(\textit{pos}, \textit{pre}, \textit{limit})$,答案为 $\textit{dfs}(\textit{0}, 0, \textit{true})$。
80
+ 我们首先获取数字 $n$ 的二进制长度,记为 $m$。然后根据题目信息,我们设计函数 $\textit{dfs}(i, \textit{pre}, \textit{limit})$,其中:
82
81
83
- 其中:
82
+ - 数字 $i$ 表示当前搜索到的位置,我们从数字的最高位开始搜索,即二进制字符串的首字符;
83
+ - 数字 $\textit{pre}$ 表示上一个数字二进制位上的数字,对于本题,$\textit{pre}$ 的初始值为 $0$;
84
+ - 布尔值 $\textit{limit}$ 表示可填的数字的限制,如果无限制,那么可以选择 $[ 0,1] $,否则,只能选择 $[ 0, \textit{up}] $。
84
85
85
- - ` pos ` 表示数字的位数,我们从数字的最高位开始,即二进制字符串的首字符;
86
- - ` pre ` 表示当前数字二进制位上的数字,对于本题,` pre ` 的初始值为 ` 0 ` ;
87
- - ` limit ` 表示可填的数字的限制,如果无限制,那么可以选择 $[ 0,1] $,否则,只能选择 $[ 0,..s[ \textit{pos}]] $。
86
+ 函数的执行过程如下:
88
87
89
- 关于函数的实现细节,可以参考下面的代码。
88
+ 如果 $i$ 超过了数字 $n$ 的长度,即 $i \lt 0$,说明搜索结束,直接返回 $1$。否则,我们从 $0$ 到 $\textit{up}$ 枚举位置 $i$ 的数字 $j$,对于每一个 $j$:
90
89
91
- 时间复杂度 $O(\log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为题目给定的数字。
90
+ - 如果 $\textit{pre}$ 和 $j$ 都为 $1$,说明有连续的 $1$,直接跳过;
91
+ - 否则,我们递归到下一层,更新 $\textit{pre}$ 为 $j$,并将 $\textit{limit}$ 更新为 $\textit{limit}$ 与 $j$ 是否等于 $\textit{up}$ 的逻辑与。
92
+
93
+ 最后,我们将所有递归到下一层的结果累加,即为答案。
94
+
95
+ 时间复杂度 $O(\log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为题目给定的正整数。
92
96
93
97
相似题目:
94
98
107
111
class Solution :
108
112
def findIntegers (self , n : int ) -> int :
109
113
@cache
110
- def dfs (pos : int , pre : int , limit : bool ) -> int :
111
- if pos == len (s) :
114
+ def dfs (i : int , pre : int , limit : bool ) -> int :
115
+ if i < 0 :
112
116
return 1
113
- up = int (s[pos] ) if limit else 1
117
+ up = (n >> i & 1 ) if limit else 1
114
118
ans = 0
115
- for i in range (up + 1 ):
116
- if pre == 1 and i == 1 :
119
+ for j in range (up + 1 ):
120
+ if pre and j :
117
121
continue
118
- ans += dfs(pos + 1 , i , limit and i == up)
122
+ ans += dfs(i - 1 , j , limit and j == up)
119
123
return ans
120
124
121
- s = bin (n)[2 :]
122
- return dfs(0 , 0 , True )
125
+ return dfs(n.bit_length() - 1 , 0 , True )
123
126
```
124
127
125
128
#### Java
126
129
127
130
``` java
128
131
class Solution {
129
- private char [] s ;
132
+ private int n ;
130
133
private Integer [][] f;
131
134
132
135
public int findIntegers (int n ) {
133
- s = Integer . toBinaryString(n). toCharArray();
134
- f = new Integer [s. length][2 ];
135
- return dfs(0 , 0 , true );
136
+ this . n = n;
137
+ int m = Integer . SIZE - Integer . numberOfLeadingZeros(n);
138
+ f = new Integer [m][2 ];
139
+ return dfs(m - 1 , 0 , true );
136
140
}
137
141
138
- private int dfs (int pos , int pre , boolean limit ) {
139
- if (pos >= s . length ) {
142
+ private int dfs (int i , int pre , boolean limit ) {
143
+ if (i < 0 ) {
140
144
return 1 ;
141
145
}
142
- if (! limit && f[pos ][pre] != null ) {
143
- return f[pos ][pre];
146
+ if (! limit && f[i ][pre] != null ) {
147
+ return f[i ][pre];
144
148
}
145
- int up = limit ? s[pos] - ' 0 ' : 1 ;
149
+ int up = limit ? (n >> i & 1 ) : 1 ;
146
150
int ans = 0 ;
147
- for (int i = 0 ; i <= up; ++ i ) {
148
- if (! (pre == 1 && i == 1 ) ) {
149
- ans += dfs(pos + 1 , i, limit && i == up) ;
151
+ for (int j = 0 ; j <= up; ++ j ) {
152
+ if (j == 1 && pre == 1 ) {
153
+ continue ;
150
154
}
155
+ ans += dfs(i - 1 , j, limit && j == up);
151
156
}
152
157
if (! limit) {
153
- f[pos ][pre] = ans;
158
+ f[i ][pre] = ans;
154
159
}
155
160
return ans;
156
161
}
@@ -163,31 +168,30 @@ class Solution {
163
168
class Solution {
164
169
public:
165
170
int findIntegers(int n) {
166
- string s = bitset<32>(n).to_string();
167
- s = s.substr(s.find('1'));
168
- int m = s.size();
171
+ int m = 32 - __ builtin_clz(n);
169
172
int f[ m] [ 2 ] ;
170
173
memset(f, -1, sizeof(f));
171
- auto dfs = [ &] (auto&& dfs, int pos , int pre, bool limit) -> int {
172
- if (pos >= m ) {
174
+ auto dfs = [ &] (auto&& dfs, int i , int pre, bool limit) -> int {
175
+ if (i < 0 ) {
173
176
return 1;
174
177
}
175
- if (!limit && f[ pos ] [ pre ] != -1) {
176
- return f[ pos ] [ pre ] ;
178
+ if (!limit && f[ i ] [ pre ] != -1) {
179
+ return f[ i ] [ pre ] ;
177
180
}
178
- int up = limit ? s [ pos ] - '0' : 1;
181
+ int up = limit ? (n >> i & 1) : 1;
179
182
int ans = 0;
180
- for (int i = 0; i <= up; ++i ) {
181
- if (!(pre == 1 && i == 1) ) {
182
- ans += dfs(dfs, pos + 1, i, limit && i == up) ;
183
+ for (int j = 0; j <= up; ++j ) {
184
+ if (j && pre ) {
185
+ continue ;
183
186
}
187
+ ans += dfs(dfs, i - 1, j, limit && j == up);
184
188
}
185
189
if (!limit) {
186
- f[ pos ] [ pre ] = ans;
190
+ f[ i ] [ pre ] = ans;
187
191
}
188
192
return ans;
189
193
};
190
- return dfs(dfs, 0 , 0, true);
194
+ return dfs(dfs, m - 1 , 0, true);
191
195
}
192
196
};
193
197
```
@@ -196,68 +200,66 @@ public:
196
200
197
201
```go
198
202
func findIntegers(n int) int {
199
- s := strconv.FormatInt(int64(n), 2)
200
- m := len(s)
201
- f := make([][]int, m)
203
+ m := bits.Len(uint(n))
204
+ f := make([][2]int, m)
202
205
for i := range f {
203
- f[i] = []int{-1, -1}
206
+ f[i] = [2 ]int{-1, -1}
204
207
}
205
- var dfs func(int, int, bool) int
206
- dfs = func(pos int , pre int, limit bool) int {
207
- if pos >= m {
208
+ var dfs func(i, pre int, limit bool) int
209
+ dfs = func(i , pre int, limit bool) int {
210
+ if i < 0 {
208
211
return 1
209
212
}
210
- if !limit && f[pos ][pre] != -1 {
211
- return f[pos ][pre]
213
+ if !limit && f[i ][pre] != -1 {
214
+ return f[i ][pre]
212
215
}
213
216
up := 1
214
217
if limit {
215
- up = int(s[pos] - '0')
218
+ up = n >> i & 1
216
219
}
217
220
ans := 0
218
- for i := 0; i <= up; i ++ {
219
- if !(pre == 1 && i == 1) {
220
- ans += dfs(pos+1, i, limit && i == up)
221
+ for j := 0; j <= up; j ++ {
222
+ if j == 1 && pre == 1 {
223
+ continue
221
224
}
225
+ ans += dfs(i-1, j, limit && j == up)
222
226
}
223
227
if !limit {
224
- f[pos ][pre] = ans
228
+ f[i ][pre] = ans
225
229
}
226
230
return ans
227
231
}
228
- return dfs(0 , 0, true)
232
+ return dfs(m-1 , 0, true)
229
233
}
230
234
```
231
235
232
236
#### TypeScript
233
237
234
238
``` ts
235
239
function findIntegers(n : number ): number {
236
- const s = n .toString (2 );
237
- const m = s .length ;
238
- const f: number [][] = Array .from ({ length: m }, () => [- 1 , - 1 ]);
239
-
240
- function dfs(pos : number , pre : number , limit : boolean ): number {
241
- if (pos >= m ) {
240
+ const m = n .toString (2 ).length ;
241
+ const f: number [][] = Array .from ({ length: m }, () => Array (2 ).fill (- 1 ));
242
+ const dfs = (i : number , pre : number , limit : boolean ): number => {
243
+ if (i < 0 ) {
242
244
return 1 ;
243
245
}
244
- if (! limit && f [pos ][pre ] !== - 1 ) {
245
- return f [pos ][pre ];
246
+ if (! limit && f [i ][pre ] !== - 1 ) {
247
+ return f [i ][pre ];
246
248
}
247
- const up = limit ? parseInt ( s [ pos ]) : 1 ;
249
+ const up = limit ? ( n >> i ) & 1 : 1 ;
248
250
let ans = 0 ;
249
- for (let i = 0 ; i <= up ; ++ i ) {
250
- if (! ( pre === 1 && i === 1 ) ) {
251
- ans += dfs ( pos + 1 , i , limit && i === up ) ;
251
+ for (let j = 0 ; j <= up ; ++ j ) {
252
+ if (pre === 1 && j === 1 ) {
253
+ continue ;
252
254
}
255
+ ans += dfs (i - 1 , j , limit && j === up );
253
256
}
254
257
if (! limit ) {
255
- f [pos ][pre ] = ans ;
258
+ f [i ][pre ] = ans ;
256
259
}
257
260
return ans ;
258
- }
259
-
260
- return dfs (0 , 0 , true );
261
+ };
262
+ return dfs (m - 1 , 0 , true );
261
263
}
262
264
```
263
265
0 commit comments