Skip to content

Commit d5c2f34

Browse files
committed
feat: add solutions to lc problem: No.1977
No.1977.Number of Ways to Separate Numbers
1 parent f6c0eb8 commit d5c2f34

File tree

6 files changed

+448
-2
lines changed

6 files changed

+448
-2
lines changed

solution/1900-1999/1977.Number of Ways to Separate Numbers/README.md

+159-1
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,180 @@
5454

5555
<!-- 这里可写通用的实现逻辑 -->
5656

57+
**方法一:动态规划 + 前缀和**
58+
59+
定义 $dp[i][j]$ 表示字符串 `num` 的前 $i$ 个字符,且最后一个数字的长度为 $j$ 时的方案数。显然答案为 $\sum_{j=0}^{n} dp[n][j]$。初始值 $dp[0][0] = 1$。
60+
61+
对于 $dp[i][j]$,对应的上一个数的结尾应该是 $i-j$,我们可以枚举 $dp[i-j][k]$,其中 $k\le j$。对于 $k \lt j$ 的部分,即长度小于 $j$ 的方案数可以直接加给 $dp[i][j]$,即 $dp[i][j] = \sum_{k=0}^{j-1} dp[i-j][k]$。因为前一个数字更短,也就意味着它比当前数更小。这里可以用前缀和优化。
62+
63+
但是当 $k=j$ 时,我们需要判断同样长度的两个数字的大小关系。如果前一个数字比当前数字大,那么这种情况是不合法的,我们不应该将其加给 $dp[i][j]$。否则,我们可以将其加给 $dp[i][j]$。这里我们可以先用 $O(n^2)$ 的时间预处理得到“最长公共前缀”,然后用 $O(1)$ 的时间判断两个同样长度的数字的大小关系。
64+
65+
时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 为字符串 `num` 的长度。
66+
5767
<!-- tabs:start -->
5868

5969
### **Python3**
6070

6171
<!-- 这里可写当前语言的特殊实现逻辑 -->
6272

6373
```python
64-
74+
class Solution:
75+
def numberOfCombinations(self, num: str) -> int:
76+
def cmp(i, j, k):
77+
x = lcp[i][j]
78+
return x >= k or num[i + x] >= num[j + x]
79+
80+
mod = 10**9 + 7
81+
n = len(num)
82+
lcp = [[0] * (n + 1) for _ in range(n + 1)]
83+
for i in range(n - 1, -1, -1):
84+
for j in range(n - 1, -1, -1):
85+
if num[i] == num[j]:
86+
lcp[i][j] = 1 + lcp[i + 1][j + 1]
87+
88+
dp = [[0] * (n + 1) for _ in range(n + 1)]
89+
dp[0][0] = 1
90+
for i in range(1, n + 1):
91+
for j in range(1, i + 1):
92+
v = 0
93+
if num[i - j] != '0':
94+
if i - j - j >= 0 and cmp(i - j, i - j - j, j):
95+
v = dp[i - j][j]
96+
else:
97+
v = dp[i - j][min(j - 1, i - j)]
98+
dp[i][j] = (dp[i][j - 1] + v) % mod
99+
return dp[n][n]
65100
```
66101

67102
### **Java**
68103

69104
<!-- 这里可写当前语言的特殊实现逻辑 -->
70105

71106
```java
107+
class Solution {
108+
private static final int MOD = (int) 1e9 + 7;
109+
110+
public int numberOfCombinations(String num) {
111+
int n = num.length();
112+
int[][] lcp = new int[n + 1][n + 1];
113+
for (int i = n - 1; i >= 0; --i) {
114+
for (int j = n - 1; j >= 0; --j) {
115+
if (num.charAt(i) == num.charAt(j)) {
116+
lcp[i][j] = 1 + lcp[i + 1][j + 1];
117+
}
118+
}
119+
}
120+
int[][] dp = new int[n + 1][n + 1];
121+
dp[0][0] = 1;
122+
for (int i = 1; i <= n; ++i) {
123+
for (int j = 1; j <= i; ++j) {
124+
int v = 0;
125+
if (num.charAt(i - j) != '0') {
126+
if (i - j - j >= 0) {
127+
int x = lcp[i - j][i - j - j];
128+
if (x >= j || num.charAt(i - j + x) >= num.charAt(i - j - j + x)) {
129+
v = dp[i - j][j];
130+
}
131+
}
132+
if (v == 0) {
133+
v = dp[i - j][Math.min(j - 1, i - j)];
134+
}
135+
}
136+
dp[i][j] = (dp[i][j - 1] + v) % MOD;
137+
}
138+
}
139+
return dp[n][n];
140+
}
141+
}
142+
```
143+
144+
### **C++**
145+
146+
```cpp
147+
class Solution {
148+
public:
149+
const int mod = 1e9 + 7;
150+
151+
int numberOfCombinations(string num) {
152+
int n = num.size();
153+
vector<vector<int>> lcp(n + 1, vector<int>(n + 1));
154+
for (int i = n - 1; i >= 0; --i) {
155+
for (int j = n - 1; j >= 0; --j) {
156+
if (num[i] == num[j]) {
157+
lcp[i][j] = 1 + lcp[i + 1][j + 1];
158+
}
159+
}
160+
}
161+
auto cmp = [&](int i, int j, int k) {
162+
int x = lcp[i][j];
163+
return x >= k || num[i + x] >= num[j + x];
164+
};
165+
vector<vector<int>> dp(n + 1, vector<int>(n + 1));
166+
dp[0][0] = 1;
167+
for (int i = 1; i <= n; ++i) {
168+
for (int j = 1; j <= i; ++j) {
169+
int v = 0;
170+
if (num[i - j] != '0') {
171+
if (i - j - j >= 0 && cmp(i - j, i - j - j, j)) {
172+
v = dp[i - j][j];
173+
} else {
174+
v = dp[i - j][min(j - 1, i - j)];
175+
}
176+
}
177+
dp[i][j] = (dp[i][j - 1] + v) % mod;
178+
}
179+
}
180+
return dp[n][n];
181+
}
182+
};
183+
```
72184

185+
### **Go**
186+
187+
```go
188+
func numberOfCombinations(num string) int {
189+
n := len(num)
190+
lcp := make([][]int, n+1)
191+
dp := make([][]int, n+1)
192+
for i := range lcp {
193+
lcp[i] = make([]int, n+1)
194+
dp[i] = make([]int, n+1)
195+
}
196+
for i := n - 1; i >= 0; i-- {
197+
for j := n - 1; j >= 0; j-- {
198+
if num[i] == num[j] {
199+
lcp[i][j] = 1 + lcp[i+1][j+1]
200+
}
201+
}
202+
}
203+
cmp := func(i, j, k int) bool {
204+
x := lcp[i][j]
205+
return x >= k || num[i+x] >= num[j+x]
206+
}
207+
dp[0][0] = 1
208+
var mod int = 1e9 + 7
209+
for i := 1; i <= n; i++ {
210+
for j := 1; j <= i; j++ {
211+
v := 0
212+
if num[i-j] != '0' {
213+
if i-j-j >= 0 && cmp(i-j, i-j-j, j) {
214+
v = dp[i-j][j]
215+
} else {
216+
v = dp[i-j][min(j-1, i-j)]
217+
}
218+
}
219+
dp[i][j] = (dp[i][j-1] + v) % mod
220+
}
221+
}
222+
return dp[n][n]
223+
}
224+
225+
func min(a, b int) int {
226+
if a < b {
227+
return a
228+
}
229+
return b
230+
}
73231
```
74232

75233
### **...**

solution/1900-1999/1977.Number of Ways to Separate Numbers/README_EN.md

+149-1
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,161 @@
5050
### **Python3**
5151

5252
```python
53-
53+
class Solution:
54+
def numberOfCombinations(self, num: str) -> int:
55+
def cmp(i, j, k):
56+
x = lcp[i][j]
57+
return x >= k or num[i + x] >= num[j + x]
58+
59+
mod = 10**9 + 7
60+
n = len(num)
61+
lcp = [[0] * (n + 1) for _ in range(n + 1)]
62+
for i in range(n - 1, -1, -1):
63+
for j in range(n - 1, -1, -1):
64+
if num[i] == num[j]:
65+
lcp[i][j] = 1 + lcp[i + 1][j + 1]
66+
67+
dp = [[0] * (n + 1) for _ in range(n + 1)]
68+
dp[0][0] = 1
69+
for i in range(1, n + 1):
70+
for j in range(1, i + 1):
71+
v = 0
72+
if num[i - j] != '0':
73+
if i - j - j >= 0 and cmp(i - j, i - j - j, j):
74+
v = dp[i - j][j]
75+
else:
76+
v = dp[i - j][min(j - 1, i - j)]
77+
dp[i][j] = (dp[i][j - 1] + v) % mod
78+
return dp[n][n]
5479
```
5580

5681
### **Java**
5782

5883
```java
84+
class Solution {
85+
private static final int MOD = (int) 1e9 + 7;
86+
87+
public int numberOfCombinations(String num) {
88+
int n = num.length();
89+
int[][] lcp = new int[n + 1][n + 1];
90+
for (int i = n - 1; i >= 0; --i) {
91+
for (int j = n - 1; j >= 0; --j) {
92+
if (num.charAt(i) == num.charAt(j)) {
93+
lcp[i][j] = 1 + lcp[i + 1][j + 1];
94+
}
95+
}
96+
}
97+
int[][] dp = new int[n + 1][n + 1];
98+
dp[0][0] = 1;
99+
for (int i = 1; i <= n; ++i) {
100+
for (int j = 1; j <= i; ++j) {
101+
int v = 0;
102+
if (num.charAt(i - j) != '0') {
103+
if (i - j - j >= 0) {
104+
int x = lcp[i - j][i - j - j];
105+
if (x >= j || num.charAt(i - j + x) >= num.charAt(i - j - j + x)) {
106+
v = dp[i - j][j];
107+
}
108+
}
109+
if (v == 0) {
110+
v = dp[i - j][Math.min(j - 1, i - j)];
111+
}
112+
}
113+
dp[i][j] = (dp[i][j - 1] + v) % MOD;
114+
}
115+
}
116+
return dp[n][n];
117+
}
118+
}
119+
```
120+
121+
### **C++**
122+
123+
```cpp
124+
class Solution {
125+
public:
126+
const int mod = 1e9 + 7;
127+
128+
int numberOfCombinations(string num) {
129+
int n = num.size();
130+
vector<vector<int>> lcp(n + 1, vector<int>(n + 1));
131+
for (int i = n - 1; i >= 0; --i) {
132+
for (int j = n - 1; j >= 0; --j) {
133+
if (num[i] == num[j]) {
134+
lcp[i][j] = 1 + lcp[i + 1][j + 1];
135+
}
136+
}
137+
}
138+
auto cmp = [&](int i, int j, int k) {
139+
int x = lcp[i][j];
140+
return x >= k || num[i + x] >= num[j + x];
141+
};
142+
vector<vector<int>> dp(n + 1, vector<int>(n + 1));
143+
dp[0][0] = 1;
144+
for (int i = 1; i <= n; ++i) {
145+
for (int j = 1; j <= i; ++j) {
146+
int v = 0;
147+
if (num[i - j] != '0') {
148+
if (i - j - j >= 0 && cmp(i - j, i - j - j, j)) {
149+
v = dp[i - j][j];
150+
} else {
151+
v = dp[i - j][min(j - 1, i - j)];
152+
}
153+
}
154+
dp[i][j] = (dp[i][j - 1] + v) % mod;
155+
}
156+
}
157+
return dp[n][n];
158+
}
159+
};
160+
```
59161

162+
### **Go**
163+
164+
```go
165+
func numberOfCombinations(num string) int {
166+
n := len(num)
167+
lcp := make([][]int, n+1)
168+
dp := make([][]int, n+1)
169+
for i := range lcp {
170+
lcp[i] = make([]int, n+1)
171+
dp[i] = make([]int, n+1)
172+
}
173+
for i := n - 1; i >= 0; i-- {
174+
for j := n - 1; j >= 0; j-- {
175+
if num[i] == num[j] {
176+
lcp[i][j] = 1 + lcp[i+1][j+1]
177+
}
178+
}
179+
}
180+
cmp := func(i, j, k int) bool {
181+
x := lcp[i][j]
182+
return x >= k || num[i+x] >= num[j+x]
183+
}
184+
dp[0][0] = 1
185+
var mod int = 1e9 + 7
186+
for i := 1; i <= n; i++ {
187+
for j := 1; j <= i; j++ {
188+
v := 0
189+
if num[i-j] != '0' {
190+
if i-j-j >= 0 && cmp(i-j, i-j-j, j) {
191+
v = dp[i-j][j]
192+
} else {
193+
v = dp[i-j][min(j-1, i-j)]
194+
}
195+
}
196+
dp[i][j] = (dp[i][j-1] + v) % mod
197+
}
198+
}
199+
return dp[n][n]
200+
}
201+
202+
func min(a, b int) int {
203+
if a < b {
204+
return a
205+
}
206+
return b
207+
}
60208
```
61209

62210
### **...**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
class Solution {
2+
public:
3+
const int mod = 1e9 + 7;
4+
5+
int numberOfCombinations(string num) {
6+
int n = num.size();
7+
vector<vector<int>> lcp(n + 1, vector<int>(n + 1));
8+
for (int i = n - 1; i >= 0; --i) {
9+
for (int j = n - 1; j >= 0; --j) {
10+
if (num[i] == num[j]) {
11+
lcp[i][j] = 1 + lcp[i + 1][j + 1];
12+
}
13+
}
14+
}
15+
auto cmp = [&](int i, int j, int k) {
16+
int x = lcp[i][j];
17+
return x >= k || num[i + x] >= num[j + x];
18+
};
19+
vector<vector<int>> dp(n + 1, vector<int>(n + 1));
20+
dp[0][0] = 1;
21+
for (int i = 1; i <= n; ++i) {
22+
for (int j = 1; j <= i; ++j) {
23+
int v = 0;
24+
if (num[i - j] != '0') {
25+
if (i - j - j >= 0 && cmp(i - j, i - j - j, j)) {
26+
v = dp[i - j][j];
27+
} else {
28+
v = dp[i - j][min(j - 1, i - j)];
29+
}
30+
}
31+
dp[i][j] = (dp[i][j - 1] + v) % mod;
32+
}
33+
}
34+
return dp[n][n];
35+
}
36+
};

0 commit comments

Comments
 (0)