Skip to content

Commit 1cd9cec

Browse files
committed
Add solution 115
1 parent 89af127 commit 1cd9cec

23 files changed

+642
-340
lines changed

README.md

Lines changed: 260 additions & 260 deletions
Large diffs are not rendered by default.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package leetcode
2+
3+
// 解法一 压缩版 DP
4+
func numDistinct(s string, t string) int {
5+
dp := make([]int, len(s)+1)
6+
for i, curT := range t {
7+
pre := 0
8+
for j, curS := range s {
9+
if i == 0 {
10+
pre = 1
11+
}
12+
newDP := dp[j+1]
13+
if curT == curS {
14+
dp[j+1] = dp[j] + pre
15+
} else {
16+
dp[j+1] = dp[j]
17+
}
18+
pre = newDP
19+
}
20+
}
21+
return dp[len(s)]
22+
}
23+
24+
// 解法二 普通 DP
25+
func numDistinct1(s, t string) int {
26+
m, n := len(s), len(t)
27+
if m < n {
28+
return 0
29+
}
30+
dp := make([][]int, m+1)
31+
for i := range dp {
32+
dp[i] = make([]int, n+1)
33+
dp[i][n] = 1
34+
}
35+
for i := m - 1; i >= 0; i-- {
36+
for j := n - 1; j >= 0; j-- {
37+
if s[i] == t[j] {
38+
dp[i][j] = dp[i+1][j+1] + dp[i+1][j]
39+
} else {
40+
dp[i][j] = dp[i+1][j]
41+
}
42+
}
43+
}
44+
return dp[0][0]
45+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package leetcode
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
)
7+
8+
type question115 struct {
9+
para115
10+
ans115
11+
}
12+
13+
// para 是参数
14+
// one 代表第一个参数
15+
type para115 struct {
16+
s string
17+
t string
18+
}
19+
20+
// ans 是答案
21+
// one 代表第一个答案
22+
type ans115 struct {
23+
one int
24+
}
25+
26+
func Test_Problem115(t *testing.T) {
27+
28+
qs := []question115{
29+
30+
{
31+
para115{"rabbbit", "rabbit"},
32+
ans115{3},
33+
},
34+
35+
{
36+
para115{"babgbag", "bag"},
37+
ans115{5},
38+
},
39+
}
40+
41+
fmt.Printf("------------------------Leetcode Problem 115------------------------\n")
42+
43+
for _, q := range qs {
44+
_, p := q.ans115, q.para115
45+
fmt.Printf("【input】:%v 【output】:%v\n", p, numDistinct(p.s, p.t))
46+
}
47+
fmt.Printf("\n\n\n")
48+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# [115. Distinct Subsequences](https://leetcode.com/problems/distinct-subsequences/)
2+
3+
4+
## 题目
5+
6+
Given two strings `s` and `t`, return *the number of distinct subsequences of `s` which equals `t`*.
7+
8+
A string's **subsequence** is a new string formed from the original string by deleting some (can be none) of the characters without disturbing the remaining characters' relative positions. (i.e., `"ACE"` is a subsequence of `"ABCDE"` while `"AEC"` is not).
9+
10+
It is guaranteed the answer fits on a 32-bit signed integer.
11+
12+
**Example 1:**
13+
14+
```
15+
Input: s = "rabbbit", t = "rabbit"
16+
Output: 3
17+
Explanation:
18+
As shown below, there are 3 ways you can generate "rabbit" from S.
19+
rabbbitrabbbitrabbbit
20+
```
21+
22+
**Example 2:**
23+
24+
```
25+
Input: s = "babgbag", t = "bag"
26+
Output: 5
27+
Explanation:
28+
As shown below, there are 5 ways you can generate "bag" from S.
29+
babgbagbabgbagbabgbagbabgbagbabgbag
30+
```
31+
32+
**Constraints:**
33+
34+
- `0 <= s.length, t.length <= 1000`
35+
- `s` and `t` consist of English letters.
36+
37+
## 题目大意
38+
39+
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE" 是 "ABCDE" 的一个子序列,而 "AEC" 不是)题目数据保证答案符合 32 位带符号整数范围。
40+
41+
## 解题思路
42+
43+
- 在字符串 `s` 中最多包含多少个字符串 `t`。这里面包含很多重叠子问题,所以尝试用动态规划解决这个问题。定义 `dp[i][j]` 代表 `s[i:]` 的子序列中 `t[j:]` 出现的个数。初始化先判断边界条件。当 `i = len(s)``0≤ j < len(t)` 的时候,`s[i:]` 为空字符串,`t[j:]` 不为空,所以 `dp[len(s)][j] = 0`。当 `j = len(t)``0 ≤ i < len(s)` 的时候,`t[j:]` 不为空字符串,空字符串是任何字符串的子序列。所以 `dp[i][n] = 1`
44+
-`i < len(s)``j < len(t)` 的时候,如果 `s[i] == t[j]`,有 2 种匹配方式,第一种将 `s[i]``t[j]` 匹配,那么 `t[j+1:]` 匹配 `s[i+1:]` 的子序列,子序列数为 `dp[i+1][j+1]`;第二种将 `s[i]` 不与 `t[j]` 匹配,`t[j:]` 作为 `s[i+1:]` 的子序列,子序列数为 `dp[i+1][j]`。综合 2 种情况,当 `s[i] == t[j]` 时,`dp[i][j] = dp[i+1][j+1] + dp[i+1][j]`
45+
- 如果 `s[i] != t[j]`,此时 `t[j:]` 只能作为 `s[i+1:]` 的子序列,子序列数为 `dp[i+1][j]`。所以当 `s[i] != t[j]` 时,`dp[i][j] = dp[i+1][j]`。综上分析得:
46+
47+
{{< katex display >}}
48+
dp[i][j] = \left\{\begin{matrix}dp[i+1][j+1]+dp[i+1][j]&,s[i]=t[j]\\ dp[i+1][j]&,s[i]!=t[j]\end{matrix}\right.
49+
{{< /katex >}}
50+
51+
- 最后是优化版本。写出上述代码以后,可以发现填表的过程是从右下角一直填到左上角。填表顺序是 从下往上一行一行的填。行内从右往左填。于是可以将这个二维数据压缩到一维。因为填充当前行只需要用到它的下一行信息即可,更进一步,用到的是下一行中右边元素的信息。于是可以每次更新该行时,先将旧的值存起来,计算更新该行的时候从右往左更新。这样做即可减少一维空间,将原来的二维数组压缩到一维数组。
52+
53+
## 代码
54+
55+
```go
56+
package leetcode
57+
58+
// 解法一 压缩版 DP
59+
func numDistinct(s string, t string) int {
60+
dp := make([]int, len(s)+1)
61+
for i, curT := range t {
62+
pre := 0
63+
for j, curS := range s {
64+
if i == 0 {
65+
pre = 1
66+
}
67+
newDP := dp[j+1]
68+
if curT == curS {
69+
dp[j+1] = dp[j] + pre
70+
} else {
71+
dp[j+1] = dp[j]
72+
}
73+
pre = newDP
74+
}
75+
}
76+
return dp[len(s)]
77+
}
78+
79+
// 解法二 普通 DP
80+
func numDistinct1(s, t string) int {
81+
m, n := len(s), len(t)
82+
if m < n {
83+
return 0
84+
}
85+
dp := make([][]int, m+1)
86+
for i := range dp {
87+
dp[i] = make([]int, n+1)
88+
dp[i][n] = 1
89+
}
90+
for i := m - 1; i >= 0; i-- {
91+
for j := n - 1; j >= 0; j-- {
92+
if s[i] == t[j] {
93+
dp[i][j] = dp[i+1][j+1] + dp[i+1][j]
94+
} else {
95+
dp[i][j] = dp[i+1][j]
96+
}
97+
}
98+
}
99+
return dp[0][0]
100+
}
101+
```

website/content/ChapterFour/0100~0199/0114.Flatten-Binary-Tree-to-Linked-List.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,5 +194,5 @@ func flatten2(root *TreeNode) {
194194
----------------------------------------------
195195
<div style="display: flex;justify-content: space-between;align-items: center;">
196196
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0100~0199/0113.Path-Sum-II/">⬅️上一页</a></p>
197-
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0100~0199/0118.Pascals-Triangle/">下一页➡️</a></p>
197+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0100~0199/0115.Distinct-Subsequences/">下一页➡️</a></p>
198198
</div>
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# [115. Distinct Subsequences](https://leetcode.com/problems/distinct-subsequences/)
2+
3+
4+
## 题目
5+
6+
Given two strings `s` and `t`, return *the number of distinct subsequences of `s` which equals `t`*.
7+
8+
A string's **subsequence** is a new string formed from the original string by deleting some (can be none) of the characters without disturbing the remaining characters' relative positions. (i.e., `"ACE"` is a subsequence of `"ABCDE"` while `"AEC"` is not).
9+
10+
It is guaranteed the answer fits on a 32-bit signed integer.
11+
12+
**Example 1:**
13+
14+
```
15+
Input: s = "rabbbit", t = "rabbit"
16+
Output: 3
17+
Explanation:
18+
As shown below, there are 3 ways you can generate "rabbit" from S.
19+
rabbbitrabbbitrabbbit
20+
```
21+
22+
**Example 2:**
23+
24+
```
25+
Input: s = "babgbag", t = "bag"
26+
Output: 5
27+
Explanation:
28+
As shown below, there are 5 ways you can generate "bag" from S.
29+
babgbagbabgbagbabgbagbabgbagbabgbag
30+
```
31+
32+
**Constraints:**
33+
34+
- `0 <= s.length, t.length <= 1000`
35+
- `s` and `t` consist of English letters.
36+
37+
## 题目大意
38+
39+
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。字符串的一个 子序列 是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE" 是 "ABCDE" 的一个子序列,而 "AEC" 不是)题目数据保证答案符合 32 位带符号整数范围。
40+
41+
## 解题思路
42+
43+
- 在字符串 `s` 中最多包含多少个字符串 `t`。这里面包含很多重叠子问题,所以尝试用动态规划解决这个问题。定义 `dp[i][j]` 代表 `s[i:]` 的子序列中 `t[j:]` 出现的个数。初始化先判断边界条件。当 `i = len(s)``0≤ j < len(t)` 的时候,`s[i:]` 为空字符串,`t[j:]` 不为空,所以 `dp[len(s)][j] = 0`。当 `j = len(t)``0 ≤ i < len(s)` 的时候,`t[j:]` 不为空字符串,空字符串是任何字符串的子序列。所以 `dp[i][n] = 1`
44+
-`i < len(s)``j < len(t)` 的时候,如果 `s[i] == t[j]`,有 2 种匹配方式,第一种将 `s[i]``t[j]` 匹配,那么 `t[j+1:]` 匹配 `s[i+1:]` 的子序列,子序列数为 `dp[i+1][j+1]`;第二种将 `s[i]` 不与 `t[j]` 匹配,`t[j:]` 作为 `s[i+1:]` 的子序列,子序列数为 `dp[i+1][j]`。综合 2 种情况,当 `s[i] == t[j]` 时,`dp[i][j] = dp[i+1][j+1] + dp[i+1][j]`
45+
- 如果 `s[i] != t[j]`,此时 `t[j:]` 只能作为 `s[i+1:]` 的子序列,子序列数为 `dp[i+1][j]`。所以当 `s[i] != t[j]` 时,`dp[i][j] = dp[i+1][j]`。综上分析得:
46+
47+
$$dp[i][j] = \left\{\begin{matrix}dp[i+1][j+1]+dp[i+1][j]&,s[i]=t[j]\\ dp[i+1][j]&,s[i]!=t[j]\end{matrix}\right.$$
48+
49+
- 最后是优化版本。写出上述代码以后,可以发现填表的过程是从右下角一直填到左上角。填表顺序是 从下往上一行一行的填。行内从右往左填。于是可以将这个二维数据压缩到一维。因为填充当前行只需要用到它的下一行信息即可,更进一步,用到的是下一行中右边元素的信息。于是可以每次更新该行时,先将旧的值存起来,计算更新该行的时候从右往左更新。这样做即可减少一维空间,将原来的二维数组压缩到一维数组。
50+
51+
## 代码
52+
53+
```go
54+
package leetcode
55+
56+
// 解法一 压缩版 DP
57+
func numDistinct(s string, t string) int {
58+
dp := make([]int, len(s)+1)
59+
for i, curT := range t {
60+
pre := 0
61+
for j, curS := range s {
62+
if i == 0 {
63+
pre = 1
64+
}
65+
newDP := dp[j+1]
66+
if curT == curS {
67+
dp[j+1] = dp[j] + pre
68+
} else {
69+
dp[j+1] = dp[j]
70+
}
71+
pre = newDP
72+
}
73+
}
74+
return dp[len(s)]
75+
}
76+
77+
// 解法二 普通 DP
78+
func numDistinct1(s, t string) int {
79+
m, n := len(s), len(t)
80+
if m < n {
81+
return 0
82+
}
83+
dp := make([][]int, m+1)
84+
for i := range dp {
85+
dp[i] = make([]int, n+1)
86+
dp[i][n] = 1
87+
}
88+
for i := m - 1; i >= 0; i-- {
89+
for j := n - 1; j >= 0; j-- {
90+
if s[i] == t[j] {
91+
dp[i][j] = dp[i+1][j+1] + dp[i+1][j]
92+
} else {
93+
dp[i][j] = dp[i+1][j]
94+
}
95+
}
96+
}
97+
return dp[0][0]
98+
}
99+
```
100+
101+
102+
----------------------------------------------
103+
<div style="display: flex;justify-content: space-between;align-items: center;">
104+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0100~0199/0114.Flatten-Binary-Tree-to-Linked-List/">⬅️上一页</a></p>
105+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0100~0199/0118.Pascals-Triangle/">下一页➡️</a></p>
106+
</div>

website/content/ChapterFour/0100~0199/0118.Pascals-Triangle.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,6 @@ func generate(numRows int) [][]int {
6262

6363
----------------------------------------------
6464
<div style="display: flex;justify-content: space-between;align-items: center;">
65-
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0100~0199/0114.Flatten-Binary-Tree-to-Linked-List/">⬅️上一页</a></p>
65+
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0100~0199/0115.Distinct-Subsequences/">⬅️上一页</a></p>
6666
<p><a href="https://books.halfrost.com/leetcode/ChapterFour/0100~0199/0119.Pascals-Triangle-II/">下一页➡️</a></p>
6767
</div>

0 commit comments

Comments
 (0)