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
@@ -67,30 +67,28 @@ tags:
67
67
68
68
这道题实际上是求在给定区间 $[ l,..r] $ 中,数字的二进制表示不包含连续的 $1$ 的个数。个数与数的位数以及每个二进制位上的数字有关。我们可以用数位 DP 的思路来解决这道题。数位 DP 中,数的大小对复杂度的影响很小。
69
69
70
- 对于区间 $[ l,..r] $ 问题,我们一般会将其转化为 $[ 1 ,..r] $ 然后再减去 $[ 1 ,..l - 1] $ 的问题,即:
70
+ 对于区间 $[ l,..r] $ 问题,我们一般会将其转化为 $[ 0 ,..r] $ 然后再减去 $[ 0 ,..l - 1] $ 的问题,即:
71
71
72
72
$$
73
- ans = \sum_{i=1 }^{r} ans_i - \sum_{i=1 }^{l-1} ans_i
73
+ ans = \sum_{i=0 }^{r} ans_i - \sum_{i=0 }^{l-1} ans_i
74
74
$$
75
75
76
76
不过对于本题而言,我们只需要求出区间 $[ 0,..r] $ 的值即可。
77
77
78
- 这里我们用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。
78
+ 这里我们用记忆化搜索来实现数位 DP。基本步骤如下:
79
79
80
- 基本步骤如下:
81
-
82
- 1 . 将数字 $n$ 转为二进制数组 $a$,其中 $a[ 1] $ 为最低位,而 $a[ len] $ 为最高位;
83
- 1 . 根据题目信息,设计函数 $dfs()$,对于本题,我们定义 $dfs(pos, pre, limit)$,答案为 $dfs(len, 1, true)$。
80
+ 1 . 将数字 $n$ 转为二进制字符串 $s$;
81
+ 1 . 根据题目信息,设计函数 $\textit{dfs}()$,对于本题,我们定义 $\textit{dfs}(\textit{pos}, \textit{pre}, \textit{limit})$,答案为 $\textit{dfs}(\textit{0}, 0, \textit{true})$。
84
82
85
83
其中:
86
84
87
- - ` pos ` 表示数字的位数,从末位或者第一位开始,一般根据题目的数字构造性质来选择顺序。对于本题,我们选择从高位开始,因此, ` pos ` 的初始值为 ` len ` ;
85
+ - ` pos ` 表示数字的位数,我们从数字的最高位开始,即二进制字符串的首字符 ;
88
86
- ` pre ` 表示当前数字二进制位上的数字,对于本题,` pre ` 的初始值为 ` 0 ` ;
89
- - ` limit ` 表示可填的数字的限制,如果无限制,那么可以选择 $[ 0,1] $,否则,只能选择 $[ 0,..a [ pos]] $。如果 ` limit ` 为 ` true ` 且已经取到了能取到的最大值,那么下一个 ` limit ` 同样为 ` true ` ;如果 ` limit ` 为 ` true ` 但是还没有取到最大值,或者 ` limit ` 为 ` false ` ,那么下一个 ` limit ` 为 ` false ` 。
87
+ - ` limit ` 表示可填的数字的限制,如果无限制,那么可以选择 $[ 0,1] $,否则,只能选择 $[ 0,..s [ \textit{ pos} ]] $。
90
88
91
89
关于函数的实现细节,可以参考下面的代码。
92
90
93
- 时间复杂度 $O(\log n)$。
91
+ 时间复杂度 $O(\log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为题目给定的数字 。
94
92
95
93
相似题目:
96
94
109
107
class Solution :
110
108
def findIntegers (self , n : int ) -> int :
111
109
@cache
112
- def dfs (pos , pre , limit ) :
113
- if pos <= 0 :
110
+ def dfs (pos : int , pre : int , limit : bool ) -> int :
111
+ if pos == len (s) :
114
112
return 1
115
- up = a [pos] if limit else 1
113
+ up = int (s [pos]) if limit else 1
116
114
ans = 0
117
115
for i in range (up + 1 ):
118
116
if pre == 1 and i == 1 :
119
117
continue
120
- ans += dfs(pos - 1 , i, limit and i == up)
118
+ ans += dfs(pos + 1 , i, limit and i == up)
121
119
return ans
122
120
123
- a = [0 ] * 33
124
- l = 0
125
- while n:
126
- l += 1
127
- a[l] = n & 1
128
- n >>= 1
129
- return dfs(l, 0 , True )
121
+ s = bin (n)[2 :]
122
+ return dfs(0 , 0 , True )
130
123
```
131
124
132
125
#### Java
133
126
134
127
``` java
135
128
class Solution {
136
- private int [] a = new int [ 33 ] ;
137
- private int [][] dp = new int [ 33 ][ 2 ] ;
129
+ private char [] s ;
130
+ private Integer [][] f ;
138
131
139
132
public int findIntegers (int n ) {
140
- int len = 0 ;
141
- while (n > 0 ) {
142
- a[++ len] = n & 1 ;
143
- n >> = 1 ;
144
- }
145
- for (var e : dp) {
146
- Arrays . fill(e, - 1 );
147
- }
148
- return dfs(len, 0 , true );
133
+ s = Integer . toBinaryString(n). toCharArray();
134
+ f = new Integer [s. length][2 ];
135
+ return dfs(0 , 0 , true );
149
136
}
150
137
151
138
private int dfs (int pos , int pre , boolean limit ) {
152
- if (pos <= 0 ) {
139
+ if (pos >= s . length ) {
153
140
return 1 ;
154
141
}
155
- if (! limit && dp [pos][pre] != - 1 ) {
156
- return dp [pos][pre];
142
+ if (! limit && f [pos][pre] != null ) {
143
+ return f [pos][pre];
157
144
}
158
- int up = limit ? a [pos] : 1 ;
145
+ int up = limit ? s [pos] - ' 0 ' : 1 ;
159
146
int ans = 0 ;
160
147
for (int i = 0 ; i <= up; ++ i) {
161
148
if (! (pre == 1 && i == 1 )) {
162
- ans += dfs(pos - 1 , i, limit && i == up);
149
+ ans += dfs(pos + 1 , i, limit && i == up);
163
150
}
164
151
}
165
152
if (! limit) {
166
- dp [pos][pre] = ans;
153
+ f [pos][pre] = ans;
167
154
}
168
155
return ans;
169
156
}
@@ -175,37 +162,32 @@ class Solution {
175
162
``` cpp
176
163
class Solution {
177
164
public:
178
- int a[ 33] ;
179
- int dp[ 33] [ 2 ] ;
180
-
181
165
int findIntegers(int n) {
182
- int len = 0;
183
- while (n) {
184
- a[++len] = n & 1;
185
- n >>= 1;
186
- }
187
- memset (dp, -1, sizeof dp);
188
- return dfs(len, 0, true);
189
- }
190
-
191
- int dfs(int pos, int pre, bool limit) {
192
- if (pos <= 0) {
193
- return 1;
194
- }
195
- if (!limit && dp[pos][pre] != -1) {
196
- return dp[pos][pre];
197
- }
198
- int ans = 0;
199
- int up = limit ? a[pos] : 1;
200
- for (int i = 0; i <= up; ++i) {
201
- if (!(pre == 1 && i == 1)) {
202
- ans += dfs(pos - 1, i, limit && i == up);
166
+ string s = bitset<32>(n).to_string();
167
+ s = s.substr(s.find('1'));
168
+ int m = s.size();
169
+ int f[ m] [ 2 ] ;
170
+ memset(f, -1, sizeof(f));
171
+ auto dfs = [ &] (auto&& dfs, int pos, int pre, bool limit) -> int {
172
+ if (pos >= m) {
173
+ return 1;
203
174
}
204
- }
205
- if (!limit) {
206
- dp[pos][pre] = ans;
207
- }
208
- return ans;
175
+ if (!limit && f[ pos] [ pre ] != -1) {
176
+ return f[ pos] [ pre ] ;
177
+ }
178
+ int up = limit ? s[ pos] - '0' : 1;
179
+ 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
+ }
184
+ }
185
+ if (!limit) {
186
+ f[ pos] [ pre ] = ans;
187
+ }
188
+ return ans;
189
+ };
190
+ return dfs(dfs, 0, 0, true);
209
191
}
210
192
};
211
193
```
@@ -214,41 +196,68 @@ public:
214
196
215
197
```go
216
198
func findIntegers(n int) int {
217
- a := make([]int, 33)
218
- dp := make([][2]int, 33)
219
- for i := range dp {
220
- dp[i] = [2]int{-1, -1}
221
- }
222
- l := 0
223
- for n > 0 {
224
- l++
225
- a[l] = n & 1
226
- n >>= 1
199
+ s := strconv.FormatInt(int64(n), 2)
200
+ m := len(s)
201
+ f := make([][]int, m)
202
+ for i := range f {
203
+ f[i] = []int{-1, -1}
227
204
}
228
205
var dfs func(int, int, bool) int
229
- dfs = func(pos, pre int, limit bool) int {
230
- if pos <= 0 {
206
+ dfs = func(pos int , pre int, limit bool) int {
207
+ if pos >= m {
231
208
return 1
232
209
}
233
- if !limit && dp [pos][pre] != -1 {
234
- return dp [pos][pre]
210
+ if !limit && f [pos][pre] != -1 {
211
+ return f [pos][pre]
235
212
}
236
213
up := 1
237
214
if limit {
238
- up = a [pos]
215
+ up = int(s [pos] - '0')
239
216
}
240
217
ans := 0
241
218
for i := 0; i <= up; i++ {
242
219
if !(pre == 1 && i == 1) {
243
- ans += dfs(pos- 1, i, limit && i == up)
220
+ ans += dfs(pos+ 1, i, limit && i == up)
244
221
}
245
222
}
246
223
if !limit {
247
- dp [pos][pre] = ans
224
+ f [pos][pre] = ans
248
225
}
249
226
return ans
250
227
}
251
- return dfs(l, 0, true)
228
+ return dfs(0, 0, true)
229
+ }
230
+ ```
231
+
232
+ #### TypeScript
233
+
234
+ ``` ts
235
+ 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 ) {
242
+ return 1 ;
243
+ }
244
+ if (! limit && f [pos ][pre ] !== - 1 ) {
245
+ return f [pos ][pre ];
246
+ }
247
+ const up = limit ? parseInt (s [pos ]) : 1 ;
248
+ 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 );
252
+ }
253
+ }
254
+ if (! limit ) {
255
+ f [pos ][pre ] = ans ;
256
+ }
257
+ return ans ;
258
+ }
259
+
260
+ return dfs (0 , 0 , true );
252
261
}
253
262
```
254
263
0 commit comments