Skip to content

Commit d9b576a

Browse files
authored
feat: add solutions to lcci problem: No.17.22 (doocs#2812)
No.17.22.Word Transformer
1 parent e4f067f commit d9b576a

File tree

10 files changed

+448
-319
lines changed

10 files changed

+448
-319
lines changed

lcci/17.22.Word Transformer/README.md

+153-105
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,19 @@ wordList = ["hot","dot","dog","lot",&quo
3333

3434
## 解法
3535

36-
### 方法一
36+
### 方法一:DFS
37+
38+
我们定义一个答案数组 $\textit{ans}$,初始时只包含 $\textit{beginWord}$。然后我们定义一个数组 $\textit{vis}$,用来标记 $\textit{wordList}$ 中的单词是否被访问过。
39+
40+
接下来,我们设计一个函数 $\text{dfs}(s)$,表示从 $\textit{s}$ 出发,尝试将 $\textit{s}$ 转换为 $\textit{endWord}$,是否能够成功。如果能够成功,返回 $\text{True}$,否则返回 $\text{False}$。
41+
42+
函数 $\text{dfs}(s)$ 的具体实现如下:
43+
44+
1. 如果 $\textit{s}$ 等于 $\textit{endWord}$,说明转换成功,返回 $\text{True}$;
45+
2. 否则,我们遍历 $\textit{wordList}$ 中的每个单词 $\textit{t}$,如果 $\textit{t}$ 没有被访问过且 $\textit{s}$ 和 $\textit{t}$ 之间只有一个字符不同,那么我们将 $\textit{t}$ 标记为已访问,并将 $\textit{t}$ 加入到 $\textit{ans}$ 中,然后递归调用 $\text{dfs}(t)$,如果返回 $\text{True}$,说明转换成功,我们返回 $\text{True}$,否则我们将 $\textit{t}$ 从 $\textit{ans}$ 中移除,继续遍历下一个单词;
46+
3. 如果遍历完 $\textit{wordList}$ 中的所有单词都没有找到可以转换的单词,说明转换失败,我们返回 $\text{False}$。
47+
48+
最后,我们调用 $\text{dfs}(\textit{beginWord})$,如果返回 $\text{True}$,说明转换成功,我们返回 $\textit{ans}$,否则返回空数组。
3749

3850
<!-- tabs:start -->
3951

@@ -42,72 +54,67 @@ class Solution:
4254
def findLadders(
4355
self, beginWord: str, endWord: str, wordList: List[str]
4456
) -> List[str]:
45-
def check(a, b):
46-
return sum(a[i] != b[i] for i in range(len(a))) == 1
47-
48-
def dfs(begin, end, t):
49-
nonlocal ans
50-
if ans:
51-
return
52-
if begin == end:
53-
ans = t.copy()
54-
return
55-
for word in wordList:
56-
if word in visited or not check(begin, word):
57-
continue
58-
visited.add(word)
59-
t.append(word)
60-
dfs(word, end, t)
61-
t.pop()
62-
63-
ans = []
64-
visited = set()
65-
dfs(beginWord, endWord, [beginWord])
66-
return ans
57+
def check(s: str, t: str) -> bool:
58+
return len(s) == len(t) and sum(a != b for a, b in zip(s, t)) == 1
59+
60+
def dfs(s: str) -> bool:
61+
if s == endWord:
62+
return True
63+
for i, t in enumerate(wordList):
64+
if not vis[i] and check(s, t):
65+
vis[i] = True
66+
ans.append(t)
67+
if dfs(t):
68+
return True
69+
ans.pop()
70+
return False
71+
72+
ans = [beginWord]
73+
vis = [False] * len(wordList)
74+
return ans if dfs(beginWord) else []
6775
```
6876

6977
```java
7078
class Solution {
71-
private List<String> words;
72-
private List<String> ans;
73-
private Set<String> visited;
79+
private List<String> ans = new ArrayList<>();
80+
private List<String> wordList;
81+
private String endWord;
82+
private boolean[] vis;
7483

7584
public List<String> findLadders(String beginWord, String endWord, List<String> wordList) {
76-
words = wordList;
77-
ans = new ArrayList<>();
78-
visited = new HashSet<>();
79-
List<String> t = new ArrayList<>();
80-
t.add(beginWord);
81-
dfs(beginWord, endWord, t);
82-
return ans;
85+
this.wordList = wordList;
86+
this.endWord = endWord;
87+
ans.add(beginWord);
88+
vis = new boolean[wordList.size()];
89+
return dfs(beginWord) ? ans : List.of();
8390
}
8491

85-
private void dfs(String begin, String end, List<String> t) {
86-
if (!ans.isEmpty()) {
87-
return;
92+
private boolean dfs(String s) {
93+
if (s.equals(endWord)) {
94+
return true;
8895
}
89-
if (Objects.equals(begin, end)) {
90-
ans = new ArrayList<>(t);
91-
return;
92-
}
93-
for (String word : words) {
94-
if (visited.contains(word) || !check(begin, word)) {
96+
for (int i = 0; i < wordList.size(); ++i) {
97+
String t = wordList.get(i);
98+
if (vis[i] || !check(s, t)) {
9599
continue;
96100
}
97-
t.add(word);
98-
visited.add(word);
99-
dfs(word, end, t);
100-
t.remove(t.size() - 1);
101+
vis[i] = true;
102+
ans.add(t);
103+
if (dfs(t)) {
104+
return true;
105+
}
106+
ans.remove(ans.size() - 1);
101107
}
108+
return false;
102109
}
103110

104-
private boolean check(String a, String b) {
105-
if (a.length() != b.length()) {
111+
private boolean check(String s, String t) {
112+
if (s.length() != t.length()) {
106113
return false;
107114
}
108115
int cnt = 0;
109-
for (int i = 0; i < a.length(); ++i) {
110-
if (a.charAt(i) != b.charAt(i)) {
116+
for (int i = 0; i < s.length(); ++i) {
117+
if (s.charAt(i) != t.charAt(i)) {
111118
++cnt;
112119
}
113120
}
@@ -119,87 +126,128 @@ class Solution {
119126
```cpp
120127
class Solution {
121128
public:
122-
vector<string> words;
123-
vector<string> ans;
124-
unordered_set<string> visited;
125-
126129
vector<string> findLadders(string beginWord, string endWord, vector<string>& wordList) {
127-
this->words = wordList;
128-
ans.resize(0);
129-
vector<string> t;
130-
t.push_back(beginWord);
131-
dfs(beginWord, endWord, t);
132-
return ans;
130+
this->endWord = move(endWord);
131+
this->wordList = move(wordList);
132+
vis.resize(this->wordList.size(), false);
133+
ans.push_back(beginWord);
134+
if (dfs(beginWord)) {
135+
return ans;
136+
}
137+
return {};
133138
}
134139

135-
void dfs(string begin, string end, vector<string>& t) {
136-
if (!ans.empty()) return;
137-
if (begin == end) {
138-
ans = t;
139-
return;
140+
private:
141+
vector<string> ans;
142+
vector<bool> vis;
143+
string endWord;
144+
vector<string> wordList;
145+
146+
bool check(string& s, string& t) {
147+
if (s.size() != t.size()) {
148+
return false;
140149
}
141-
for (auto word : words) {
142-
if (visited.count(word) || !check(begin, word)) continue;
143-
visited.insert(word);
144-
t.push_back(word);
145-
dfs(word, end, t);
146-
t.pop_back();
150+
int cnt = 0;
151+
for (int i = 0; i < s.size(); ++i) {
152+
cnt += s[i] != t[i];
147153
}
154+
return cnt == 1;
148155
}
149156

150-
bool check(string a, string b) {
151-
if (a.size() != b.size()) return false;
152-
int cnt = 0;
153-
for (int i = 0; i < a.size(); ++i)
154-
if (a[i] != b[i]) ++cnt;
155-
return cnt == 1;
157+
bool dfs(string& s) {
158+
if (s == endWord) {
159+
return true;
160+
}
161+
for (int i = 0; i < wordList.size(); ++i) {
162+
string& t = wordList[i];
163+
if (!vis[i] && check(s, t)) {
164+
vis[i] = true;
165+
ans.push_back(t);
166+
if (dfs(t)) {
167+
return true;
168+
}
169+
ans.pop_back();
170+
}
171+
}
172+
return false;
156173
}
157174
};
158175
```
159176

160177
```go
161178
func findLadders(beginWord string, endWord string, wordList []string) []string {
162-
var ans []string
163-
visited := make(map[string]bool)
164-
165-
check := func(a, b string) bool {
166-
if len(a) != len(b) {
179+
ans := []string{beginWord}
180+
vis := make([]bool, len(wordList))
181+
check := func(s, t string) bool {
182+
if len(s) != len(t) {
167183
return false
168184
}
169185
cnt := 0
170-
for i := 0; i < len(a); i++ {
171-
if a[i] != b[i] {
186+
for i := range s {
187+
if s[i] != t[i] {
172188
cnt++
173189
}
174190
}
175191
return cnt == 1
176192
}
177-
178-
var dfs func(begin, end string, t []string)
179-
dfs = func(begin, end string, t []string) {
180-
if len(ans) > 0 {
181-
return
182-
}
183-
if begin == end {
184-
ans = make([]string, len(t))
185-
copy(ans, t)
186-
return
193+
var dfs func(s string) bool
194+
dfs = func(s string) bool {
195+
if s == endWord {
196+
return true
187197
}
188-
for _, word := range wordList {
189-
if visited[word] || !check(begin, word) {
190-
continue
198+
for i, t := range wordList {
199+
if !vis[i] && check(s, t) {
200+
vis[i] = true
201+
ans = append(ans, t)
202+
if dfs(t) {
203+
return true
204+
}
205+
ans = ans[:len(ans)-1]
191206
}
192-
t = append(t, word)
193-
visited[word] = true
194-
dfs(word, end, t)
195-
t = t[:len(t)-1]
196207
}
208+
return false
197209
}
210+
if dfs(beginWord) {
211+
return ans
212+
}
213+
return []string{}
214+
}
215+
```
198216

199-
var t []string
200-
t = append(t, beginWord)
201-
dfs(beginWord, endWord, t)
202-
return ans
217+
```ts
218+
function findLadders(beginWord: string, endWord: string, wordList: string[]): string[] {
219+
const ans: string[] = [beginWord];
220+
const vis: boolean[] = Array(wordList.length).fill(false);
221+
const check = (s: string, t: string): boolean => {
222+
if (s.length !== t.length) {
223+
return false;
224+
}
225+
let cnt = 0;
226+
for (let i = 0; i < s.length; ++i) {
227+
if (s[i] !== t[i]) {
228+
++cnt;
229+
}
230+
}
231+
return cnt === 1;
232+
};
233+
const dfs = (s: string): boolean => {
234+
if (s === endWord) {
235+
return true;
236+
}
237+
for (let i = 0; i < wordList.length; ++i) {
238+
const t: string = wordList[i];
239+
if (!vis[i] && check(s, t)) {
240+
vis[i] = true;
241+
ans.push(t);
242+
if (dfs(t)) {
243+
return true;
244+
}
245+
ans.pop();
246+
}
247+
}
248+
return false;
249+
};
250+
return dfs(beginWord) ? ans : [];
203251
}
204252
```
205253

0 commit comments

Comments
 (0)