Skip to content

Commit 324cf5d

Browse files
committed
2017/5/13 17:09
1 parent ba96474 commit 324cf5d

13 files changed

+1001
-699
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Introduction
22

3-
This book provides C++/Go solutions for all leetcode problems.
3+
This book provides C++ && Go solutions for all leetcode problems.
44

5-
Chapters are categorized into two big sets: **Data structures** and **Algorithms**.
5+
Chapters are divided into two categories: **Data structures** and **Algorithms**.
66

77
### 1. Data structures
88

@@ -11,6 +11,7 @@ Chapters are categorized into two big sets: **Data structures** and **Algorithms
1111
* String
1212
* Hash Table
1313
* Stack
14+
* Queue
1415
* Heap
1516
* Graph
1617
* Bit Manipulation

SUMMARY.md

+275-274
Large diffs are not rendered by default.

backtracking/all.sh all.sh

File renamed without changes.

array/118.PascalsTriangle.md

+33
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,37 @@ Return
2222
[[LeetCode 119] Pascal's Triangle II]()
2323

2424
#### Analysis
25+
先理解 Pascal Triangle 的特征:
26+
27+
- 每一列第一个值都是 1。
28+
- 每一列第 n 个值则是上一列 n-1 位置和 n 位置的值之和。
29+
- 假如是该列最后一个值 Nx,前一列没有 Nx 这个值,可以视为 0。
30+
31+
##### Solutions
32+
33+
```cpp
34+
class Solution {
35+
public:
36+
vector<vector<int>> generate(int numRows) {
37+
vector<vector<int>> res;
38+
if(numRows < 1) return res;
39+
vector<int> row(1, 1);
40+
res.push_back(row);
41+
for(int i = 2; i <= numRows; i++) {
42+
int prev = 1;
43+
for(int j = 1; j < i - 1; j++) {
44+
int temp = row[j];
45+
row[j] += prev;
46+
prev = temp;
47+
}
48+
row.push_back(1);
49+
res.push_back(row);
50+
}
51+
return res;
52+
}
53+
};
54+
```
55+
56+
57+
##### Reference
2558
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

dynamic_programming/115.DistinctSubsequences.md

+154
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,162 @@ Return `3`.
1818

1919

2020
#### Analysis
21+
这题题意是要求在 S 中的所有包含 T 的不同子序列的数量。比如题例中就包含三个:"bbbit", "abbbit", "rabbbit",这三个子序列均包含了 T 。
2122

23+
看到有关字符串的子序列或者配准类的问题,首先应该考虑的就是用动态规划 Dynamic Programming 来求解,而且,要考虑空字符串的情况,因为空串也是任意字符串的一个子序列。
24+
DP 类型的题惯例的三步走:定义状态,推导递推公式,确定状态计算方向和起始状态。
25+
把 DP[i][j] 定义为 S[0:j-1] 中存在包含 T[0:i-1] 的 distinct subsequence 的个数。显然如果 j < i,DP[i][j] = 0。
2226

27+
也可以这样想,设母串的长度为 j,子串的长度为 i,我们要求的就是长度为 i 的子串在长度为 j 的母串的所有子串中出现的次数,设为 dp[i][j]
2328

29+
考虑下列两种情况:
2430

31+
- 若母串的最后一个字符与子串的最后一个字符不同(`S[j] != T[i]`),则长度为 i 的子串在长度为 j 的母串中出现的次数就是母串的前 j - 1 个字符中子串出现的次数,即 dp[i][j] = dp[i][j - 1]
32+
- 若母串的最后一个字符与子串的最后一个字符相同(`S[j] == T[i]`),那么最终数量是下列两种情况相加,也即 dp[i][j] = dp[i][j - 1] + t[i - 1][j - 1]
33+
+ 母串的前 j - 1 个字符也可能出现整个子串,T[0:i]
34+
+ 母串的前 j - 1 个字符出现子串的前 i - 1个字符,T[0:i-1]
2535

36+
转换方程:
37+
38+
DP[i][j] = DP[i][j-1], S[j-1] != T[i-1]
39+
DP[i][j] = DP[i-1][j-1] + DP[i][j-1], S[j-1] == T[i-1]
40+
41+
初始值:
42+
43+
先设置第 0 行、第 0 列的值。
44+
45+
第 0 列:DP[i][0] = 0,i > 0。 S 是空字符串,T 不是空字符串,显然 T 不可能成为 S 的 subsequence。
46+
第 0 行:DP[0][j] = 1,j >= 0。T 是空字符串,那么显然是 S 的 1 个 subsequence
47+
48+
**优化**
49+
由于只跟上一次结果有关,可以使用滚动数组来减小空间复杂度。
50+
51+
对于二维数组的解集矩阵来说,实际上只有上三角(或者下三角)的数据是有效的,因此可以通过求矩阵上三角(或者下三角)的方式来缩减空间,比如:
52+
53+
— r a b b i t
54+
- 1 0 0 0 0 0 0
55+
r 1 1 0 0 0 0 0
56+
a 1 1 1 0 0 0 0
57+
b 1 1 1 1 0 0 0
58+
b 1 1 1 2 1 0 0
59+
b 1 1 1 3 3 0 0
60+
i 1 1 1 3 3 3 0
61+
t 1 1 1 3 3 3 3
62+
图(一)
63+
64+
或者
65+
66+
— r a b b b i t
67+
- 1 1 1 1 1 1 1 1
68+
r 0 1 1 1 1 1 1 1
69+
a 0 0 1 1 1 1 1 1
70+
b 0 0 0 1 2 3 3 3
71+
b 0 0 0 0 1 3 3 3
72+
i 0 0 0 0 0 0 3 3
73+
t 0 0 0 0 0 0 0 3
74+
图(二)
75+
76+
77+
78+
知道了解集的结构之后,我们就可以使用一维数组,然后按照上图所示的方式来进行遍历。图一应该是从右往左遍历,图二则是从左往右遍历。
79+
因为当发生 S[i] == T[j] 的时候,dp[j] = dp[j] + dp[j - 1]
80+
81+
##### Solutions
82+
83+
1. DP With 2D Array
84+
85+
```cpp
86+
class Solution {
87+
public:
88+
int numDistinct(string s, string t) {
89+
int m = s.length(), n = t.length();
90+
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
91+
92+
for (int i = 0; i <= m; ++i) dp[0][i] = 1;
93+
for (int i = 1; i <= n; ++i) {
94+
for (int j = 1; j <= m; ++j) {
95+
if (s[j - 1] != t[i - 1]) dp[i][j] = dp[i][j - 1];
96+
else {
97+
dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];
98+
}
99+
}
100+
}
101+
return dp[n][m];
102+
}
103+
};
104+
```
105+
106+
正序
107+
108+
```cpp
109+
class Solution {
110+
public:
111+
int numDistinct(string s, string t) {
112+
int m = s.length(), n = t.length();
113+
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
114+
for (int i = 0; i <= m; ++i) dp[i][0] = 1;
115+
for (int i = 1; i <= m; ++i) {
116+
for (int j = 1; j <= n; ++j) {
117+
if (s[i - 1] != t[j - 1]) dp[i][j] = dp[i - 1][j];
118+
else {
119+
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
120+
}
121+
}
122+
}
123+
return dp[m][n];
124+
}
125+
};
126+
```
127+
128+
2. DP With 1D Array
129+
j 从尾到头,因为每次要使用上一次 loop 的值。如果从头往尾扫的话,重复计算了。
130+
131+
```cpp
132+
class Solution {
133+
public:
134+
int numDistinct(string s, string t) {
135+
int m = s.length(), n = t.length();
136+
if (m < n) return 0;
137+
vector<int> dp(n + 1, 0);
138+
dp[0] = 1; // 相当于 dp[0][0],肯定是 1
139+
for (int i = 1; i <= m; ++i) {
140+
for (int j = n; j >= 1; --j) { // 从后往前
141+
if (s[i - 1] == t[j - 1]) {
142+
dp[j] += dp[j - 1];
143+
}
144+
}
145+
}
146+
return dp[n];
147+
}
148+
};
149+
```
150+
151+
3. DP With 1D Array
152+
153+
```cpp
154+
class Solution {
155+
public:
156+
int numDistinct(string s, string t) {
157+
int n = s.size(), m = t.size();
158+
vector<int> dp(n + 1, 1);
159+
160+
for(int i = 1; i <= m; i++) {
161+
int upLeft = dp[0];
162+
dp[0] = 0;
163+
for(int j = 1; j <= n; j++) {
164+
int temp = dp[j];
165+
dp[j] = dp[j - 1];
166+
if(s[j - 1] == t[i - 1])
167+
dp[j] += upLeft;
168+
upLeft = temp;
169+
}
170+
}
171+
172+
return dp[n];
173+
}
174+
};
175+
```
176+
177+
#### Reference
178+
179+
[LeetCode 115]:https://leetcode.com/problems/distinct-subsequences

0 commit comments

Comments
 (0)