Skip to content

Commit 0afe228

Browse files
committed
重构, bugfix
1 parent 4a5e30e commit 0afe228

11 files changed

+497
-368
lines changed

C++/LeetCodet题解(C++版).pdf

4.26 KB
Binary file not shown.

C++/chapBFS.tex

Lines changed: 95 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -43,37 +43,50 @@ \subsubsection{代码}
4343
//LeetCode, Word Ladder
4444
class Solution {
4545
public:
46-
int ladderLength(string start, string end, unordered_set<string> &dict) {
46+
typedef string state_t;
47+
int ladderLength(string start, string end,
48+
const unordered_set<string> &dict) {
4749
if (start.size() != end.size()) return 0;
48-
if (start.empty() || end.empty()) return 1; return 0;
49-
int level = 1; // 层次
50-
queue<string> queToPush, queToPop;
51-
52-
queToPop.push(start);
53-
while (dict.size() > 0 && !queToPop.empty()) {
54-
while (!queToPop.empty()) {
55-
string str(queToPop.front());
56-
queToPop.pop();
57-
for (int i = 0; i < str.size(); i++) {
58-
for (char j = 'a'; j <= 'z'; j++) {
59-
if (j == str[i]) continue;
60-
61-
const char temp = str[i];
62-
str[i] = j;
63-
if (str == end) return level + 1; //找到了
64-
65-
if (dict.count(str) > 0) {
66-
queToPush.push(str);
67-
dict.erase(str); // 删除该单词,防止死循环
50+
if (start.empty() || end.empty()) return 0;
51+
52+
queue<string> next, current; // 当前层,下一层
53+
unordered_set<string> visited; // 判重
54+
unordered_map<string, string > father;
55+
int level = 0; // 层次
56+
bool found = false;
57+
58+
current.push(start);
59+
while (!current.empty() && !found) {
60+
++level;
61+
while (!current.empty() && !found) {
62+
const string str(current.front()); current.pop();
63+
64+
for (size_t i = 0; i < str.size(); ++i) {
65+
string new_word(str);
66+
for (char c = 'a'; c <= 'z'; c++) {
67+
if (c == new_word[i]) continue;
68+
69+
swap(c, new_word[i]);
70+
if (new_word == end) {
71+
found = true; //找到了
72+
father[new_word] = str;
73+
break;
6874
}
69-
str[i] = temp; // 恢复该单词
75+
76+
if (dict.count(new_word) > 0
77+
&& !visited.count(new_word)) {
78+
next.push(new_word);
79+
visited.insert(new_word);
80+
father[new_word] = str;
81+
}
82+
swap(c, new_word[i]); // 恢复该单词
7083
}
7184
}
7285
}
73-
swap(queToPush, queToPop); //!!! 交换两个队列
74-
level++;
86+
swap(next, current); //!!! 交换两个队列
7587
}
76-
return 0; // 所有单词已经用光,还是找不到通向目标单词的路径
88+
if (found) return level+1;
89+
else return 0;
7790
}
7891
};
7992
\end{Code}
@@ -119,90 +132,80 @@ \subsubsection{描述}
119132

120133

121134
\subsubsection{分析}
122-
跟 Word Ladder比,这题是求路径本身,不是路径长度,也是BFS,略微麻烦点
135+
跟 Word Ladder比,这题是求路径本身,不是路径长度,也是BFS,略微麻烦点。
136+
137+
这题跟普通的广搜有很大的不同,就是要输出所有路径,因此在记录前驱和判重地方与普通广搜略有不同。
123138

124139

125140
\subsubsection{代码}
126141

127142
\begin{Code}
128143
//LeetCode, Word Ladder II
129-
//跟 Word Ladder比,这题是求路径本身,不是路径长度,也是BFS,略微麻烦点
130144
class Solution {
131145
public:
132-
std::vector<std::vector<std::string> > findLadders(std::string start,
133-
std::string end, std::unordered_set<std::string> &dict) {
134-
result_.clear();
135-
std::unordered_map<std::string, std::vector<std::string>> prevMap;
136-
137-
for (auto iter = dict.begin(); iter != dict.end(); ++iter) {
138-
prevMap[*iter] = std::vector<std::string>();
139-
}
140-
141-
std::vector<std::unordered_set<std::string>> candidates(2);
142-
143-
int current = 0;
144-
int previous = 1;
145-
146-
candidates[current].insert(start);
147-
148-
while (true) {
149-
current = !current;
150-
previous = !previous;
151-
152-
// 从dict中删除previous中的单词,避免自己指向自己
153-
for (auto iter = candidates[previous].begin();
154-
iter != candidates[previous].end(); ++iter) {
155-
dict.erase(*iter);
156-
}
157-
158-
candidates[current].clear();
159-
160-
for (auto iter = candidates[previous].begin();
161-
iter != candidates[previous].end(); ++iter) {
162-
for (size_t pos = 0; pos < iter->size(); ++pos) {
163-
std::string word = *iter;
164-
for (int i = 'a'; i <= 'z'; ++i) {
165-
if (word[pos] == i) continue;
166-
167-
word[pos] = i;
168-
169-
if (dict.count(word) > 0) {
170-
prevMap[word].push_back(*iter);
171-
candidates[current].insert(word);
146+
vector<vector<string> > findLadders(string start, string end,
147+
const unordered_set<string> &dict) {
148+
unordered_set<string> visited; // 判重
149+
unordered_map<string, vector<string> > father; // 树
150+
unordered_set<string> current, next; // 当前层,下一层,用集合是为了去重
151+
152+
int level = 0; // 层数
153+
bool found = false;
154+
155+
current.insert(start);
156+
while (!current.empty() && !found) {
157+
++level;
158+
// 先将本层全部置为已访问,防止同层之间互相指向
159+
for (auto iter = current.begin(); iter != current.end(); ++iter)
160+
visited.insert(*iter);
161+
for (auto iter = current.begin(); iter != current.end(); ++iter) {
162+
//while (!current.empty()) {
163+
const string word = *iter;
164+
165+
for (size_t i = 0; i < word.size(); ++i) {
166+
string new_word = word;
167+
for (char c = 'a'; c <= 'z'; ++c) {
168+
if (c == new_word[i]) continue;
169+
swap(c, new_word[i]);
170+
171+
if (new_word == end) found = true; //找到了
172+
173+
if (visited.count(new_word) == 0
174+
&& (dict.count(new_word) > 0 ||
175+
new_word == end)) {
176+
next.insert(new_word);
177+
father[new_word].push_back(word);
178+
// visited.insert(new_word)移动到最上面了
172179
}
180+
181+
swap(c, new_word[i]); // restore
173182
}
174183
}
175184
}
176185

177-
if (candidates[current].size() == 0) return result_; // 此题无解
178-
if (candidates[current].count(end)) break; // 没看懂
186+
current.clear();
187+
swap(current, next);
179188
}
180-
181-
std::vector<std::string> path;
182-
GeneratePath(prevMap, path, end);
183-
184-
return result_;
189+
vector<vector<string> > result;
190+
if (found) {
191+
vector<string> path;
192+
buildPath(father, path, start, end, result);
193+
}
194+
return result;
185195
}
186-
187196
private:
188-
std::vector<std::vector<std::string>> result_;
189-
190-
void GeneratePath(
191-
std::unordered_map<std::string, std::vector<std::string>> &prevMap,
192-
std::vector<std::string>& path, const std::string& word) {
193-
if (prevMap[word].size() == 0) {
194-
path.push_back(word);
195-
std::vector<std::string> curPath = path;
196-
reverse(curPath.begin(), curPath.end());
197-
result_.push_back(curPath);
198-
path.pop_back();
199-
return;
200-
}
201-
197+
void buildPath(unordered_map<string, vector<string> > &father,
198+
vector<string> &path, const string &start, const string &word,
199+
vector<vector<string> > &result) {
202200
path.push_back(word);
203-
for (auto iter = prevMap[word].begin(); iter != prevMap[word].end();
204-
++iter) {
205-
GeneratePath(prevMap, path, *iter);
201+
if (word == start) {
202+
result.push_back(path);
203+
reverse(result.back().begin(), result.back().end());
204+
} else {
205+
for (auto iter = father[word].begin(); iter != father[word].end();
206+
++iter) {
207+
buildPath(father, path, start, *iter, result);
208+
}
206209
}
207210
path.pop_back();
208211
}

C++/chapBruteforce.tex

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ \subsection{二进制法}
116116
\subsubsection{代码}
117117
\begin{Code}
118118
// LeetCode, Subsets
119-
// 二进制法,也可以看做是位向量法,只不过更加优化
119+
// 二进制法
120120
class Solution {
121121
public:
122122
vector<vector<int> > subsets(vector<int> &S) {
@@ -176,6 +176,58 @@ \subsubsection{分析}
176176
\subsubsection{代码}
177177
\begin{Code}
178178
// LeetCode, Subsets II
179+
// 增量构造法
180+
class Solution {
181+
public:
182+
vector<vector<int> > subsetsWithDup(vector<int> &S) {
183+
vector<vector<int> > result;
184+
std::sort(S.begin(), S.end()); // 本题对顺序有要求,需要排序
185+
186+
unordered_map<int, int> count_map; // 记录每个元素的出现次数
187+
std::for_each(S.begin(), S.end(), [&count_map](int e) {
188+
if (count_map.find(e) != count_map.end())
189+
count_map[e]++;
190+
else
191+
count_map[e] = 1;
192+
});
193+
194+
// 将map里的pair拷贝到一个vector里
195+
std::vector<pair<int, int> > elems;
196+
std::for_each(count_map.begin(), count_map.end(),
197+
[&elems](const pair<int, int> &e) {
198+
elems.push_back(e);
199+
});
200+
std::sort(elems.begin(), elems.end());
201+
std::vector<int> path; // 中间结果
202+
203+
subsets(elems, 0, path, result);
204+
return result;
205+
}
206+
207+
private:
208+
static void subsets(const std::vector<pair<int, int> > &elems,
209+
size_t step, vector<int> &path, vector<vector<int> > &result) {
210+
if (step == elems.size()) {
211+
result.push_back(path);
212+
return;
213+
}
214+
215+
for (int i = 0; i <= elems[step].second; i++) {
216+
for (int j = 0; j < i; ++j) {
217+
path.push_back(elems[step].first);
218+
}
219+
subsets(elems, step + 1, path, result);
220+
for (int j = 0; j < i; ++j) {
221+
path.pop_back();
222+
}
223+
}
224+
}
225+
};
226+
\end{Code}
227+
228+
\begin{Code}
229+
// LeetCode, Subsets II
230+
// 位向量法
179231
class Solution {
180232
public:
181233
vector<vector<int> > subsetsWithDup(vector<int> &S) {
@@ -300,9 +352,9 @@ \subsubsection{代码}
300352

301353
// Scan from right to left, find the first element that is greater than
302354
// `pivot`.
303-
auto pos = find_if(rfirst, pivot, bind1st(less<int>(), *pivot));
355+
auto change = find_if(rfirst, pivot, bind1st(less<int>(), *pivot));
304356

305-
swap(*pos, *pivot);
357+
swap(*change, *pivot);
306358
reverse(rfirst, pivot);
307359

308360
return true;
@@ -415,15 +467,17 @@ \subsubsection{代码}
415467
vector<vector<int>> result; // 最终结果
416468
vector<int> p; // 中间结果
417469

418-
permute(num.size(), elems.begin(), elems.end(), 0, p, result);
470+
n = num.size();
471+
permute(elems.begin(), elems.end(), p, result);
419472
return result;
420473
}
421474

422475
private:
476+
size_t n;
423477
typedef std::vector<pair<int, int> >::const_iterator Iter;
424478

425-
void permute(const size_t n, Iter first, Iter last,
426-
vector<int> &p, vector<vector<int> > &result) {
479+
void permute(Iter first, Iter last, vector<int> &p,
480+
vector<vector<int> > &result) {
427481
if (n == p.size()) { // 收敛条件
428482
result.push_back(p);
429483
}
@@ -438,7 +492,7 @@ \subsubsection{代码}
438492
}
439493
if (count < i->second) {
440494
p.push_back(i->first);
441-
permute(n, first, last, p, result);
495+
permute(first, last, p, result);
442496
p.pop_back(); // 撤销动作,返回上一层
443497
}
444498
}

C++/chapDFS.tex

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ \subsubsection{代码}
109109
int m, n;
110110

111111
int uniquePathsRecursive(int x, int y) {
112-
if (x < 1 or x > m) return 0; // 数据非法
113-
if (y < 1 or y > n) return 0;
112+
if (x < 1 || x > m) return 0; // 数据非法
113+
if (y < 1 || y > n) return 0;
114114

115-
if (x == 1 and y == 1) return 1; // 终止条件
115+
if (x == 1 && y == 1) return 1; // 终止条件
116116

117117
return uniquePathsRecursive(x - 1, y) + uniquePathsRecursive(x, y - 1);
118118
}
@@ -141,10 +141,10 @@ \subsubsection{代码}
141141
vector<vector<int> > f; // 缓存
142142

143143
int uniquePathsRecursive(int x, int y) {
144-
if (x < 1 or x > m) return 0; // 数据非法,终止条件
145-
if (y < 1 or y > n) return 0;
144+
if (x < 1 || x > m) return 0; // 数据非法,终止条件
145+
if (y < 1 || y > n) return 0;
146146

147-
if (x == 1 and y == 1) return 1; // 回到起点,收敛条件
147+
if (x == 1 && y == 1) return 1; // 回到起点,收敛条件
148148

149149
return cachedUniquePathsRecursive(x - 1, y) +
150150
cachedUniquePathsRecursive(x, y - 1);
@@ -279,8 +279,8 @@ \subsubsection{代码}
279279

280280
int uniquePathsRecursive(const vector<vector<int> > &obstacleGrid,
281281
int x, int y) {
282-
if (x < 1 or x > obstacleGrid.size()) return 0; // 数据非法,终止条件
283-
if (y < 1 or y > obstacleGrid[0].size()) return 0;
282+
if (x < 1 || x > obstacleGrid.size()) return 0; // 数据非法,终止条件
283+
if (y < 1 || y > obstacleGrid[0].size()) return 0;
284284

285285
// (x,y)是障碍
286286
if (obstacleGrid[x-1][y-1]) return 0;

0 commit comments

Comments
 (0)