Skip to content

Commit 9686c56

Browse files
authored
feat: add solutions to lc/lcof2 problems: Distinct Subsequences (doocs#1480)
lc No.0115 & lcof2 No.097.Distinct Subsequences
1 parent ffe5989 commit 9686c56

File tree

13 files changed

+624
-297
lines changed

13 files changed

+624
-297
lines changed

lcof2/剑指 Offer II 097. 子序列的数目/README.md

+177-42
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,31 @@
5454

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

57-
动态规划,`dp[i][j]` 表示 `s[:i]` 的子序列中 `t[:j]` 的出现次数
57+
**方法一:动态规划**
58+
59+
我们定义 $f[i][j]$ 表示字符串 $s$ 的前 $i$ 个字符中,子序列构成字符串 $t$ 的前 $j$ 个字符的方案数。初始时 $f[i][0]=1$,其中 $i \in [0,m]$。
60+
61+
当 $i \gt 0$ 时,考虑 $f[i][j]$ 的计算:
62+
63+
- 当 $s[i-1] \ne t[j-1]$ 时,不能选取 $s[i-1]$,因此 $f[i][j]=f[i-1][j]$;
64+
- 否则,可以选取 $s[i-1]$,此时 $f[i][j]=f[i-1][j-1]$。
65+
66+
因此我们有如下的状态转移方程:
67+
68+
$$
69+
f[i][j]=\left\{
70+
\begin{aligned}
71+
&f[i-1][j], &s[i-1] \ne t[j-1] \\
72+
&f[i-1][j-1]+f[i-1][j], &s[i-1]=t[j-1]
73+
\end{aligned}
74+
\right.
75+
$$
76+
77+
最终的答案即为 $f[m][n]$,其中 $m$ 和 $n$ 分别是字符串 $s$ 和 $t$ 的长度。
78+
79+
时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。
80+
81+
我们注意到 $f[i][j]$ 的计算只和 $f[i-1][..]$ 有关,因此,我们可以优化掉第一维,这样空间复杂度可以降低到 $O(n)$。
5882

5983
<!-- tabs:start -->
6084

@@ -66,15 +90,27 @@
6690
class Solution:
6791
def numDistinct(self, s: str, t: str) -> int:
6892
m, n = len(s), len(t)
69-
dp = [[0] * (n + 1) for _ in range(m + 1)]
93+
f = [[0] * (n + 1) for _ in range(m + 1)]
7094
for i in range(m + 1):
71-
dp[i][0] = 1
72-
for i in range(1, m + 1):
73-
for j in range(1, n + 1):
74-
dp[i][j] = dp[i - 1][j]
75-
if s[i - 1] == t[j - 1]:
76-
dp[i][j] += dp[i - 1][j - 1]
77-
return dp[m][n]
95+
f[i][0] = 1
96+
for i, a in enumerate(s, 1):
97+
for j, b in enumerate(t, 1):
98+
f[i][j] = f[i - 1][j]
99+
if a == b:
100+
f[i][j] += f[i - 1][j - 1]
101+
return f[m][n]
102+
```
103+
104+
```python
105+
class Solution:
106+
def numDistinct(self, s: str, t: str) -> int:
107+
n = len(t)
108+
f = [1] + [0] * n
109+
for a in s:
110+
for j in range(n, 0, -1):
111+
if a == t[j - 1]:
112+
f[j] += f[j - 1]
113+
return f[n]
78114
```
79115

80116
### **Java**
@@ -84,69 +120,168 @@ class Solution:
84120
```java
85121
class Solution {
86122
public int numDistinct(String s, String t) {
87-
int m = s.length();
88-
int n = t.length();
89-
int[][] dp = new int[m + 1][n + 1];
90-
for (int i = 0; i <= m; i++) {
91-
dp[i][0] = 1;
123+
int m = s.length(), n = t.length();
124+
int[][] f = new int[m + 1][n + 1];
125+
for (int i = 0; i < m + 1; ++i) {
126+
f[i][0] = 1;
92127
}
93-
for (int i = 1; i <= m; i++) {
94-
for (int j = 1; j <= n; j++) {
95-
dp[i][j] = dp[i - 1][j];
128+
for (int i = 1; i < m + 1; ++i) {
129+
for (int j = 1; j < n + 1; ++j) {
130+
f[i][j] = f[i - 1][j];
96131
if (s.charAt(i - 1) == t.charAt(j - 1)) {
97-
dp[i][j] += dp[i - 1][j - 1];
132+
f[i][j] += f[i - 1][j - 1];
133+
}
134+
}
135+
}
136+
return f[m][n];
137+
}
138+
}
139+
```
140+
141+
```java
142+
class Solution {
143+
public int numDistinct(String s, String t) {
144+
int n = t.length();
145+
int[] f = new int[n + 1];
146+
f[0] = 1;
147+
for (char a : s.toCharArray()) {
148+
for (int j = n; j > 0; --j) {
149+
char b = t.charAt(j - 1);
150+
if (a == b) {
151+
f[j] += f[j - 1];
98152
}
99153
}
100154
}
101-
return dp[m][n];
155+
return f[n];
102156
}
103157
}
104158
```
105159

160+
### **C++**
161+
162+
```cpp
163+
class Solution {
164+
public:
165+
int numDistinct(string s, string t) {
166+
int m = s.size(), n = t.size();
167+
unsigned long long f[m + 1][n + 1];
168+
memset(f, 0, sizeof(f));
169+
for (int i = 0; i < m + 1; ++i) {
170+
f[i][0] = 1;
171+
}
172+
for (int i = 1; i < m + 1; ++i) {
173+
for (int j = 1; j < n + 1; ++j) {
174+
f[i][j] = f[i - 1][j];
175+
if (s[i - 1] == t[j - 1]) {
176+
f[i][j] += f[i - 1][j - 1];
177+
}
178+
}
179+
}
180+
return f[m][n];
181+
}
182+
};
183+
```
184+
185+
```cpp
186+
class Solution {
187+
public:
188+
int numDistinct(string s, string t) {
189+
int n = t.size();
190+
unsigned long long f[n + 1];
191+
memset(f, 0, sizeof(f));
192+
f[0] = 1;
193+
for (char& a : s) {
194+
for (int j = n; j; --j) {
195+
char b = t[j - 1];
196+
if (a == b) {
197+
f[j] += f[j - 1];
198+
}
199+
}
200+
}
201+
return f[n];
202+
}
203+
};
204+
```
205+
106206
### **Go**
107207

108208
```go
109209
func numDistinct(s string, t string) int {
110210
m, n := len(s), len(t)
111-
dp := make([][]int, m+1)
211+
f := make([][]int, m+1)
212+
for i := range f {
213+
f[i] = make([]int, n+1)
214+
}
112215
for i := 0; i <= m; i++ {
113-
dp[i] = make([]int, n+1)
114-
dp[i][0] = 1
216+
f[i][0] = 1
115217
}
116218
for i := 1; i <= m; i++ {
117219
for j := 1; j <= n; j++ {
118-
dp[i][j] = dp[i-1][j]
220+
f[i][j] = f[i-1][j]
119221
if s[i-1] == t[j-1] {
120-
dp[i][j] += dp[i-1][j-1]
222+
f[i][j] += f[i-1][j-1]
121223
}
122224
}
123225
}
124-
return dp[m][n]
226+
return f[m][n]
125227
}
126228
```
127229

128-
### **C++**
230+
```go
231+
func numDistinct(s string, t string) int {
232+
n := len(t)
233+
f := make([]int, n+1)
234+
f[0] = 1
235+
for _, a := range s {
236+
for j := n; j > 0; j-- {
237+
if b := t[j-1]; byte(a) == b {
238+
f[j] += f[j-1]
239+
}
240+
}
241+
}
242+
return f[n]
243+
}
244+
```
129245

130-
```cpp
131-
class Solution {
132-
public:
133-
int numDistinct(string s, string t) {
134-
int m = s.size(), n = t.size();
135-
vector<vector<unsigned long long>> dp(m + 1, vector<unsigned long long>(n + 1));
136-
for (int i = 0; i <= m; ++i) {
137-
dp[i][0] = 1;
246+
### **TypeScript**
247+
248+
```ts
249+
function numDistinct(s: string, t: string): number {
250+
const m = s.length;
251+
const n = t.length;
252+
const f: number[][] = new Array(m + 1)
253+
.fill(0)
254+
.map(() => new Array(n + 1).fill(0));
255+
for (let i = 0; i <= m; ++i) {
256+
f[i][0] = 1;
257+
}
258+
for (let i = 1; i <= m; ++i) {
259+
for (let j = 1; j <= n; ++j) {
260+
f[i][j] = f[i - 1][j];
261+
if (s[i - 1] === t[j - 1]) {
262+
f[i][j] += f[i - 1][j - 1];
263+
}
138264
}
139-
for (int i = 1; i <= m; ++i) {
140-
for (int j = 1; j <= n; ++j) {
141-
dp[i][j] = dp[i - 1][j];
142-
if (s[i - 1] == t[j - 1]) {
143-
dp[i][j] += dp[i - 1][j - 1];
144-
}
265+
}
266+
return f[m][n];
267+
}
268+
```
269+
270+
```ts
271+
function numDistinct(s: string, t: string): number {
272+
const n = t.length;
273+
const f: number[] = new Array(n + 1).fill(0);
274+
f[0] = 1;
275+
for (const a of s) {
276+
for (let j = n; j; --j) {
277+
const b = t[j - 1];
278+
if (a === b) {
279+
f[j] += f[j - 1];
145280
}
146281
}
147-
return dp[m][n];
148282
}
149-
};
283+
return f[n];
284+
}
150285
```
151286

152287
### **...**
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
class Solution {
2-
public:
3-
int numDistinct(string s, string t) {
4-
int m = s.size(), n = t.size();
5-
vector<vector<unsigned long long>> dp(m + 1, vector<unsigned long long>(n + 1));
6-
for (int i = 0; i <= m; ++i) {
7-
dp[i][0] = 1;
8-
}
9-
for (int i = 1; i <= m; ++i) {
10-
for (int j = 1; j <= n; ++j) {
11-
dp[i][j] = dp[i - 1][j];
12-
if (s[i - 1] == t[j - 1]) {
13-
dp[i][j] += dp[i - 1][j - 1];
14-
}
15-
}
16-
}
17-
return dp[m][n];
18-
}
19-
};
1+
class Solution {
2+
public:
3+
int numDistinct(string s, string t) {
4+
int n = t.size();
5+
unsigned long long f[n + 1];
6+
memset(f, 0, sizeof(f));
7+
f[0] = 1;
8+
for (char& a : s) {
9+
for (int j = n; j; --j) {
10+
char b = t[j - 1];
11+
if (a == b) {
12+
f[j] += f[j - 1];
13+
}
14+
}
15+
}
16+
return f[n];
17+
}
18+
};
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
func numDistinct(s string, t string) int {
2-
m, n := len(s), len(t)
3-
dp := make([][]int, m+1)
4-
for i := 0; i <= m; i++ {
5-
dp[i] = make([]int, n+1)
6-
dp[i][0] = 1
7-
}
8-
for i := 1; i <= m; i++ {
9-
for j := 1; j <= n; j++ {
10-
dp[i][j] = dp[i-1][j]
11-
if s[i-1] == t[j-1] {
12-
dp[i][j] += dp[i-1][j-1]
2+
n := len(t)
3+
f := make([]int, n+1)
4+
f[0] = 1
5+
for _, a := range s {
6+
for j := n; j > 0; j-- {
7+
if b := t[j-1]; byte(a) == b {
8+
f[j] += f[j-1]
139
}
1410
}
1511
}
16-
return dp[m][n]
12+
return f[n]
1713
}
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
class Solution {
2-
public int numDistinct(String s, String t) {
3-
int m = s.length();
4-
int n = t.length();
5-
int[][] dp = new int[m + 1][n + 1];
6-
for (int i = 0; i <= m; i++) {
7-
dp[i][0] = 1;
8-
}
9-
for (int i = 1; i <= m; i++) {
10-
for (int j = 1; j <= n; j++) {
11-
dp[i][j] = dp[i - 1][j];
12-
if (s.charAt(i - 1) == t.charAt(j - 1)) {
13-
dp[i][j] += dp[i - 1][j - 1];
14-
}
15-
}
16-
}
17-
return dp[m][n];
18-
}
19-
}
1+
class Solution {
2+
public int numDistinct(String s, String t) {
3+
int n = t.length();
4+
int[] f = new int[n + 1];
5+
f[0] = 1;
6+
for (char a : s.toCharArray()) {
7+
for (int j = n; j > 0; --j) {
8+
char b = t.charAt(j - 1);
9+
if (a == b) {
10+
f[j] += f[j - 1];
11+
}
12+
}
13+
}
14+
return f[n];
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
class Solution:
2-
def numDistinct(self, s: str, t: str) -> int:
3-
m, n = len(s), len(t)
4-
dp = [[0] * n + 1 for _ in range(m + 1)]
5-
for i in range(m + 1):
6-
dp[i][0] = 1
7-
for i in range(1, m + 1):
8-
for j in range(1, n + 1):
9-
dp[i][j] = dp[i - 1][j]
10-
if s[i - 1] == s[j - 1]:
11-
dp[i][j] += dp[i - 1][j - 1]
12-
return dp[m][n]
1+
class Solution:
2+
def numDistinct(self, s: str, t: str) -> int:
3+
n = len(t)
4+
f = [1] + [0] * n
5+
for a in s:
6+
for j in range(n, 0, -1):
7+
if a == t[j - 1]:
8+
f[j] += f[j - 1]
9+
return f[n]

0 commit comments

Comments
 (0)