Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

feat: add solutions to lc problem: No.3032 #2330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 194 additions & 1 deletion solution/3000-3099/3032.Count Numbers With Unique Digits II/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,217 @@ Given two <strong>positive</strong> integers <code>a</code> and <code>b</code>,

## 解法

### 方法一
### 方法一:状态压缩 + 数位 DP

题目要求统计区间 $[a, b]$ 中的数中有多少个数的数位是唯一的,我们可以使用状态压缩和数位 DP 来解决这个问题。

我们可以用一个函数 $f(n)$ 来统计 $[1, n]$ 中的数中有多少个数的数位是唯一的,那么答案就是 $f(b) - f(a - 1)$。

另外,我们可以用一个二进制数来记录数字中出现过的数字,比如数字中出现了 $1, 3, 5$,那么我们可以用 $10101$ 来表示这个状态。

接下来,我们使用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。

基本步骤如下:

1. 我们将数字 $n$ 转换为字符串 $num$,其中 $num[0]$ 为最高位,而 $num[len - 1]$ 为最低位。
2. 根据题目信息,设计一个函数 $dfs(pos, mask, limit)$,其中 $pos$ 表示当前处理的位置,$mask$ 表示当前数字中出现过的数字,$limit$ 表示当前位置是否有限制。如果 $limit$ 为真,那么当前位置的数字不能超过 $num[pos]$。

答案为 $dfs(0, 0, true)$。

时间复杂度 $O(m \times 2^{10} \times 10)$,空间复杂度 $O(m \times 2^{10})$。其中 $m$ 为 $b$ 的位数。

<!-- tabs:start -->

```python
class Solution:
def numberCount(self, a: int, b: int) -> int:
@cache
def dfs(pos: int, mask: int, limit: bool) -> int:
if pos >= len(num):
return 1 if mask else 0
up = int(num[pos]) if limit else 9
ans = 0
for i in range(up + 1):
if mask >> i & 1:
continue
nxt = 0 if mask == 0 and i == 0 else mask | 1 << i
ans += dfs(pos + 1, nxt, limit and i == up)
return ans

num = str(a - 1)
x = dfs(0, 0, True)
dfs.cache_clear()
num = str(b)
y = dfs(0, 0, True)
return y - x
```

```java
class Solution {
private String num;
private Integer[][] f;

public int numberCount(int a, int b) {
num = String.valueOf(a - 1);
f = new Integer[num.length()][1 << 10];
int x = dfs(0, 0, true);
num = String.valueOf(b);
f = new Integer[num.length()][1 << 10];
int y = dfs(0, 0, true);
return y - x;
}

private int dfs(int pos, int mask, boolean limit) {
if (pos >= num.length()) {
return mask > 0 ? 1 : 0;
}
if (!limit && f[pos][mask] != null) {
return f[pos][mask];
}
int up = limit ? num.charAt(pos) - '0' : 9;
int ans = 0;
for (int i = 0; i <= up; ++i) {
if ((mask >> i & 1) == 1) {
continue;
}
int nxt = mask == 0 && i == 0 ? 0 : mask | 1 << i;
ans += dfs(pos + 1, nxt, limit && i == up);
}
if (!limit) {
f[pos][mask] = ans;
}
return ans;
}
}
```

```cpp
class Solution {
public:
int numberCount(int a, int b) {
string num = to_string(b);
int f[num.size()][1 << 10];
memset(f, -1, sizeof(f));
function<int(int, int, bool)> dfs = [&](int pos, int mask, bool limit) {
if (pos >= num.size()) {
return mask ? 1 : 0;
}
if (!limit && f[pos][mask] != -1) {
return f[pos][mask];
}
int up = limit ? num[pos] - '0' : 9;
int ans = 0;
for (int i = 0; i <= up; ++i) {
if (mask >> i & 1) {
continue;
}
int nxt = mask == 0 && i == 0 ? 0 : mask | 1 << i;
ans += dfs(pos + 1, nxt, limit && i == up);
}
if (!limit) {
f[pos][mask] = ans;
}
return ans;
};

int y = dfs(0, 0, true);
num = to_string(a - 1);
memset(f, -1, sizeof(f));
int x = dfs(0, 0, true);
return y - x;
}
};
```

```go
func numberCount(a int, b int) int {
num := strconv.Itoa(b)
f := make([][1 << 10]int, len(num))
for i := range f {
for j := range f[i] {
f[i][j] = -1
}
}
var dfs func(pos, mask int, limit bool) int
dfs = func(pos, mask int, limit bool) int {
if pos >= len(num) {
if mask != 0 {
return 1
}
return 0
}
if !limit && f[pos][mask] != -1 {
return f[pos][mask]
}
up := 9
if limit {
up = int(num[pos] - '0')
}
ans := 0
for i := 0; i <= up; i++ {
if mask>>i&1 == 1 {
continue
}
nxt := mask | 1<<i
if mask == 0 && i == 0 {
nxt = 0
}
ans += dfs(pos+1, nxt, limit && i == up)
}
if !limit {
f[pos][mask] = ans
}
return ans
}
y := dfs(0, 0, true)
num = strconv.Itoa(a - 1)
for i := range f {
for j := range f[i] {
f[i][j] = -1
}
}
x := dfs(0, 0, true)
return y - x
}
```

```ts
function numberCount(a: number, b: number): number {
let num: string = b.toString();
const f: number[][] = Array(num.length)
.fill(0)
.map(() => Array(1 << 10).fill(-1));
const dfs: (pos: number, mask: number, limit: boolean) => number = (pos, mask, limit) => {
if (pos >= num.length) {
return mask ? 1 : 0;
}
if (!limit && f[pos][mask] !== -1) {
return f[pos][mask];
}
const up: number = limit ? +num[pos] : 9;
let ans: number = 0;
for (let i = 0; i <= up; i++) {
if ((mask >> i) & 1) {
continue;
}
let nxt: number = mask | (1 << i);
if (mask === 0 && i === 0) {
nxt = 0;
}
ans += dfs(pos + 1, nxt, limit && i === up);
}
if (!limit) {
f[pos][mask] = ans;
}
return ans;
};

const y: number = dfs(0, 0, true);
num = (a - 1).toString();
f.forEach(v => v.fill(-1));
const x: number = dfs(0, 0, true);
return y - x;
}
```

<!-- tabs:end -->
Expand Down
Loading