Skip to content

Commit 1b3cee5

Browse files
authored
feat: add solutions to lc problem: No.0600 (#3362)
No.0600.Non-negative Integers without Consecutive Ones
1 parent f54cc81 commit 1b3cee5

File tree

7 files changed

+301
-241
lines changed

7 files changed

+301
-241
lines changed

solution/0600-0699/0600.Non-negative Integers without Consecutive Ones/README.md

Lines changed: 95 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ tags:
2525
<pre>
2626
<strong>输入:</strong> n = 5
2727
<strong>输出:</strong> 5
28-
<strong>解释:</strong>
28+
<strong>解释:</strong>
2929
下面列出范围在 [0, 5] 的非负整数与其对应的二进制表示:
3030
0 : 0
3131
1 : 1
@@ -67,30 +67,28 @@ tags:
6767

6868
这道题实际上是求在给定区间 $[l,..r]$ 中,数字的二进制表示不包含连续的 $1$ 的个数。个数与数的位数以及每个二进制位上的数字有关。我们可以用数位 DP 的思路来解决这道题。数位 DP 中,数的大小对复杂度的影响很小。
6969

70-
对于区间 $[l,..r]$ 问题,我们一般会将其转化为 $[1,..r]$ 然后再减去 $[1,..l - 1]$ 的问题,即:
70+
对于区间 $[l,..r]$ 问题,我们一般会将其转化为 $[0,..r]$ 然后再减去 $[0,..l - 1]$ 的问题,即:
7171

7272
$$
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
7474
$$
7575

7676
不过对于本题而言,我们只需要求出区间 $[0,..r]$ 的值即可。
7777

78-
这里我们用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。
78+
这里我们用记忆化搜索来实现数位 DP。基本步骤如下:
7979

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})$。
8482

8583
其中:
8684

87-
- `pos` 表示数字的位数,从末位或者第一位开始,一般根据题目的数字构造性质来选择顺序。对于本题,我们选择从高位开始,因此,`pos` 的初始值为 `len`
85+
- `pos` 表示数字的位数,我们从数字的最高位开始,即二进制字符串的首字符
8886
- `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}]]$。
9088

9189
关于函数的实现细节,可以参考下面的代码。
9290

93-
时间复杂度 $O(\log n)$。
91+
时间复杂度 $O(\log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为题目给定的数字
9492

9593
相似题目:
9694

@@ -109,61 +107,50 @@ $$
109107
class Solution:
110108
def findIntegers(self, n: int) -> int:
111109
@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):
114112
return 1
115-
up = a[pos] if limit else 1
113+
up = int(s[pos]) if limit else 1
116114
ans = 0
117115
for i in range(up + 1):
118116
if pre == 1 and i == 1:
119117
continue
120-
ans += dfs(pos - 1, i, limit and i == up)
118+
ans += dfs(pos + 1, i, limit and i == up)
121119
return ans
122120

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)
130123
```
131124

132125
#### Java
133126

134127
```java
135128
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;
138131

139132
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);
149136
}
150137

151138
private int dfs(int pos, int pre, boolean limit) {
152-
if (pos <= 0) {
139+
if (pos >= s.length) {
153140
return 1;
154141
}
155-
if (!limit && dp[pos][pre] != -1) {
156-
return dp[pos][pre];
142+
if (!limit && f[pos][pre] != null) {
143+
return f[pos][pre];
157144
}
158-
int up = limit ? a[pos] : 1;
145+
int up = limit ? s[pos] - '0' : 1;
159146
int ans = 0;
160147
for (int i = 0; i <= up; ++i) {
161148
if (!(pre == 1 && i == 1)) {
162-
ans += dfs(pos - 1, i, limit && i == up);
149+
ans += dfs(pos + 1, i, limit && i == up);
163150
}
164151
}
165152
if (!limit) {
166-
dp[pos][pre] = ans;
153+
f[pos][pre] = ans;
167154
}
168155
return ans;
169156
}
@@ -175,37 +162,32 @@ class Solution {
175162
```cpp
176163
class Solution {
177164
public:
178-
int a[33];
179-
int dp[33][2];
180-
181165
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;
203174
}
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);
209191
}
210192
};
211193
```
@@ -214,41 +196,68 @@ public:
214196
215197
```go
216198
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}
227204
}
228205
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 {
231208
return 1
232209
}
233-
if !limit && dp[pos][pre] != -1 {
234-
return dp[pos][pre]
210+
if !limit && f[pos][pre] != -1 {
211+
return f[pos][pre]
235212
}
236213
up := 1
237214
if limit {
238-
up = a[pos]
215+
up = int(s[pos] - '0')
239216
}
240217
ans := 0
241218
for i := 0; i <= up; i++ {
242219
if !(pre == 1 && i == 1) {
243-
ans += dfs(pos-1, i, limit && i == up)
220+
ans += dfs(pos+1, i, limit && i == up)
244221
}
245222
}
246223
if !limit {
247-
dp[pos][pre] = ans
224+
f[pos][pre] = ans
248225
}
249226
return ans
250227
}
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);
252261
}
253262
```
254263

0 commit comments

Comments
 (0)