@@ -43,37 +43,50 @@ \subsubsection{代码}
43
43
//LeetCode, Word Ladder
44
44
class Solution {
45
45
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) {
47
49
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;
68
74
}
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]); // 恢复该单词
70
83
}
71
84
}
72
85
}
73
- swap(queToPush, queToPop); //!!! 交换两个队列
74
- level++;
86
+ swap(next, current); //!!! 交换两个队列
75
87
}
76
- return 0; // 所有单词已经用光,还是找不到通向目标单词的路径
88
+ if (found) return level+1;
89
+ else return 0;
77
90
}
78
91
};
79
92
\end {Code }
@@ -119,90 +132,80 @@ \subsubsection{描述}
119
132
120
133
121
134
\subsubsection {分析 }
122
- 跟 Word Ladder比,这题是求路径本身,不是路径长度,也是BFS,略微麻烦点
135
+ 跟 Word Ladder比,这题是求路径本身,不是路径长度,也是BFS,略微麻烦点。
136
+
137
+ 这题跟普通的广搜有很大的不同,就是要输出所有路径,因此在记录前驱和判重地方与普通广搜略有不同。
123
138
124
139
125
140
\subsubsection {代码 }
126
141
127
142
\begin {Code }
128
143
//LeetCode, Word Ladder II
129
- //跟 Word Ladder比,这题是求路径本身,不是路径长度,也是BFS,略微麻烦点
130
144
class Solution {
131
145
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)移动到最上面了
172
179
}
180
+
181
+ swap(c, new_word[i]); // restore
173
182
}
174
183
}
175
184
}
176
185
177
- if (candidates[ current].size() == 0) return result_; // 此题无解
178
- if (candidates[ current].count(end)) break; // 没看懂
186
+ current.clear();
187
+ swap( current, next);
179
188
}
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;
185
195
}
186
-
187
196
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) {
202
200
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
+ }
206
209
}
207
210
path.pop_back();
208
211
}
0 commit comments