Skip to content
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

feat: add solutions to lc problem: No.0233 #3539

Merged
merged 2 commits into from
Sep 20, 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
229 changes: 127 additions & 102 deletions solution/0200-0299/0233.Number of Digit One/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,22 @@ $$

基本步骤如下:

1. 将数字 $n$ 转为 int 数组 $a$,其中 $a[1]$ 为最低位,而 $a[len]$ 为最高位;
1. 根据题目信息,设计函数 $dfs()$,对于本题,我们定义 $dfs(pos, cnt, limit)$,答案为 $dfs(len, 0, true)$。
我们首先将数字 $n$ 转化为字符串 $s$。然后我们设计一个函数 $\textit{dfs}(i, \textit{cnt}, \textit{limit})$,其中:

其中:
- 数字 $i$ 表示当前搜索到的位置,我们从高位开始搜索,即 $i = 0$ 表示最高位。
- 数字 $\textit{cnt}$ 表示当前数字中 $1$ 出现的次数。
- 布尔值 $\textit{limit}$ 表示当前是否受到上界的限制。

- `pos` 表示数字的位数,从末位或者第一位开始,一般根据题目的数字构造性质来选择顺序。对于本题,我们选择从高位开始,因此,`pos` 的初始值为 `len`;
- `cnt` 表示当前数字中包含的 $1$ 的个数。
- `limit` 表示可填的数字的限制,如果无限制,那么可以选择 $[0,1,..9]$,否则,只能选择 $[0,..a[pos]]$。如果 `limit` 为 `true` 且已经取到了能取到的最大值,那么下一个 `limit` 同样为 `true`;如果 `limit` 为 `true` 但是还没有取到最大值,或者 `limit` 为 `false`,那么下一个 `limit` 为 `false`。
函数的执行过程如下:

关于函数的实现细节,可以参考下面的代码。
如果 $i$ 超过了数字 $n$ 的长度,说明搜索结束,直接返回 $cnt$。如果 $\textit{limit}$ 为真,那么 $up$ 为当前数字的第 $i$ 位,否则 $up = 9$。接下来,我们遍历 $j$ 从 $0$ 到 $up$,对于每一个 $j$:

时间复杂度 $O(\log n)$。
- 如果 $j$ 等于 $1$,我们将 $cnt$ 加一。
- 递归调用 $\textit{dfs}(i + 1, \textit{cnt}, \textit{limit} \land j = up)$。

答案为 $\textit{dfs}(0, 0, \text{True})$。

时间复杂度 $O(m^2 \times D)$,空间复杂度 $O(m^2)$。其中 $m$ 为数字 $n$ 的长度,而 $D = 10$。

相似题目:

Expand All @@ -96,57 +100,48 @@ $$
class Solution:
def countDigitOne(self, n: int) -> int:
@cache
def dfs(pos, cnt, limit):
if pos <= 0:
def dfs(i: int, cnt: int, limit: bool) -> int:
if i >= len(s):
return cnt
up = a[pos] if limit else 9
up = int(s[i]) if limit else 9
ans = 0
for i in range(up + 1):
ans += dfs(pos - 1, cnt + (i == 1), limit and i == up)
for j in range(up + 1):
ans += dfs(i + 1, cnt + (j == 1), limit and j == up)
return ans

a = [0] * 12
l = 1
while n:
a[l] = n % 10
n //= 10
l += 1
return dfs(l, 0, True)
s = str(n)
return dfs(0, 0, True)
```

#### Java

```java
class Solution {
private int[] a = new int[12];
private int[][] dp = new int[12][12];
private int m;
private char[] s;
private Integer[][] f;

public int countDigitOne(int n) {
int len = 0;
while (n > 0) {
a[++len] = n % 10;
n /= 10;
}
for (var e : dp) {
Arrays.fill(e, -1);
}
return dfs(len, 0, true);
s = String.valueOf(n).toCharArray();
m = s.length;
f = new Integer[m][m];
return dfs(0, 0, true);
}

private int dfs(int pos, int cnt, boolean limit) {
if (pos <= 0) {
private int dfs(int i, int cnt, boolean limit) {
if (i >= m) {
return cnt;
}
if (!limit && dp[pos][cnt] != -1) {
return dp[pos][cnt];
if (!limit && f[i][cnt] != null) {
return f[i][cnt];
}
int up = limit ? a[pos] : 9;
int up = limit ? s[i] - '0' : 9;
int ans = 0;
for (int i = 0; i <= up; ++i) {
ans += dfs(pos - 1, cnt + (i == 1 ? 1 : 0), limit && i == up);
for (int j = 0; j <= up; ++j) {
ans += dfs(i + 1, cnt + (j == 1 ? 1 : 0), limit && j == up);
}
if (!limit) {
dp[pos][cnt] = ans;
f[i][cnt] = ans;
}
return ans;
}
Expand All @@ -158,35 +153,29 @@ class Solution {
```cpp
class Solution {
public:
int a[12];
int dp[12][12];

int countDigitOne(int n) {
int len = 0;
while (n) {
a[++len] = n % 10;
n /= 10;
}
memset(dp, -1, sizeof dp);
return dfs(len, 0, true);
}

int dfs(int pos, int cnt, bool limit) {
if (pos <= 0) {
return cnt;
}
if (!limit && dp[pos][cnt] != -1) {
return dp[pos][cnt];
}
int ans = 0;
int up = limit ? a[pos] : 9;
for (int i = 0; i <= up; ++i) {
ans += dfs(pos - 1, cnt + (i == 1), limit && i == up);
}
if (!limit) {
dp[pos][cnt] = ans;
}
return ans;
string s = to_string(n);
int m = s.size();
int f[m][m];
memset(f, -1, sizeof(f));
auto dfs = [&](auto&& dfs, int i, int cnt, bool limit) -> int {
if (i >= m) {
return cnt;
}
if (!limit && f[i][cnt] != -1) {
return f[i][cnt];
}
int up = limit ? s[i] - '0' : 9;
int ans = 0;
for (int j = 0; j <= up; ++j) {
ans += dfs(dfs, i + 1, cnt + (j == 1), limit && j == up);
}
if (!limit) {
f[i][cnt] = ans;
}
return ans;
};
return dfs(dfs, 0, 0, true);
}
};
```
Expand All @@ -195,67 +184,103 @@ public:

```go
func countDigitOne(n int) int {
a := make([]int, 12)
dp := make([][]int, 12)
for i := range dp {
dp[i] = make([]int, 12)
for j := range dp[i] {
dp[i][j] = -1
s := strconv.Itoa(n)
m := len(s)
f := make([][]int, m)
for i := range f {
f[i] = make([]int, m)
for j := range f[i] {
f[i][j] = -1
}
}
l := 0
for n > 0 {
l++
a[l] = n % 10
n /= 10
}
var dfs func(int, int, bool) int
dfs = func(pos, cnt int, limit bool) int {
if pos <= 0 {
var dfs func(i, cnt int, limit bool) int
dfs = func(i, cnt int, limit bool) int {
if i >= m {
return cnt
}
if !limit && dp[pos][cnt] != -1 {
return dp[pos][cnt]
if !limit && f[i][cnt] != -1 {
return f[i][cnt]
}
up := 9
if limit {
up = a[pos]
up = int(s[i] - '0')
}
ans := 0
for i := 0; i <= up; i++ {
t := cnt
if i == 1 {
t++
for j := 0; j <= up; j++ {
t := 0
if j == 1 {
t = 1
}
ans += dfs(pos-1, t, limit && i == up)
ans += dfs(i+1, cnt+t, limit && j == up)
}
if !limit {
dp[pos][cnt] = ans
f[i][cnt] = ans
}
return ans
}
return dfs(l, 0, true)
return dfs(0, 0, true)
}
```

#### TypeScript

```ts
function countDigitOne(n: number): number {
const s = n.toString();
const m = s.length;
const f: number[][] = Array.from({ length: m }, () => Array(m).fill(-1));
const dfs = (i: number, cnt: number, limit: boolean): number => {
if (i >= m) {
return cnt;
}
if (!limit && f[i][cnt] !== -1) {
return f[i][cnt];
}
const up = limit ? +s[i] : 9;
let ans = 0;
for (let j = 0; j <= up; ++j) {
ans += dfs(i + 1, cnt + (j === 1 ? 1 : 0), limit && j === up);
}
if (!limit) {
f[i][cnt] = ans;
}
return ans;
};
return dfs(0, 0, true);
}
```

#### C#

```cs
public class Solution {
private int m;
private char[] s;
private int?[,] f;

public int CountDigitOne(int n) {
if (n <= 0) return 0;
if (n < 10) return 1;
return CountDigitOne(n / 10 - 1) * 10 + n / 10 + CountDigitOneOfN(n / 10) * (n % 10 + 1) + (n % 10 >= 1 ? 1 : 0);
s = n.ToString().ToCharArray();
m = s.Length;
f = new int?[m, m];
return Dfs(0, 0, true);
}

private int CountDigitOneOfN(int n) {
var count = 0;
while (n > 0)
{
if (n % 10 == 1) ++count;
n /= 10;
private int Dfs(int i, int cnt, bool limit) {
if (i >= m) {
return cnt;
}
return count;
if (!limit && f[i, cnt] != null) {
return f[i, cnt].Value;
}
int up = limit ? s[i] - '0' : 9;
int ans = 0;
for (int j = 0; j <= up; ++j) {
ans += Dfs(i + 1, cnt + (j == 1 ? 1 : 0), limit && j == up);
}
if (!limit) {
f[i, cnt] = ans;
}
return ans;
}
}
```
Expand Down
Loading
Loading