LeetCode/solutions/127. Word Ladder.md
2019-07-08 23:25:30 +08:00

123 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# [127. Word Ladder](https://leetcode.com/problems/word-ladder/)
# 思路
词句阶梯: 给了我们一个单词字典,里面有一系列很相似的单词,然后给了一个起始单词和一个结束单词,每次变换只能改变一个单词,并且中间过程的单词都必须是单词字典中的单词,让我们求出最短的变化序列的长度。
要求最短路径长度首先应该想到BFS。类似迷宫里面的最短路求法迷宫每个点有上下左右四个方向可以走而这里有26个字母就是二十六个方向可以走本质上没有区别。
另外由于需要频繁判断某个单词是否在字典中所以我们用hashSet记录词典代码中的`wordSet`)以快速进行判断。
## 思路一
采用递归的BFS。首先我们用一个词语数组`beginWords`来记录开始的词语,初始化为一个元素`beginWord`,此外类似走迷宫的题目我们还需要一个`visited`来记录当前词语是否被访问过这里我们用hashSet来定义`visited`。递归出口是`beginWords`为空。
## 思路二、思路一改进
仔细分析我们可以发现了个hashSet`wordSet`和`visited`其实在功能上是有冗余的: 如果我们每访问一次`wordSet`里的词然后就把它从`wordSet`中去掉,这样不就不需要`visited`了吗?亲测会比思路一快很多。
## 思路三
思路二的非递归版本。此时就不需要`beginWords`了而需要一个队列。
# C++
## 思路一
``` C++
class Solution {
private:
int BFS(vector<string>beginWords, unordered_set<string>&wordSet,
unordered_set<string>&visited, string &endWord){
vector<string>next_beginWords;
string word;
for(int i = 0; i < beginWords.size(); i++){
for(int j = 0; j < endWord.size(); j++){
word = beginWords[i];
if(word == endWord) return 1;
for(char k = 'a'; k <= 'z'; k++){
word[j] = k;
if(!wordSet.count(word) || visited.count(word)) continue;
visited.insert(word);
next_beginWords.push_back(word);
}
}
}
if(next_beginWords.empty()) return 0; // 递归出口
return BFS(next_beginWords, wordSet, visited, endWord) + 1;
}
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string>wordSet(wordList.begin(), wordList.end());
unordered_set<string>visited{beginWord};
if(wordSet.count(endWord) != 1) return 0;
vector<string>beginWords{beginWord};
return BFS(beginWords, wordSet, visited, endWord);
}
};
```
## 思路二
``` C++
class Solution {
private:
int BFS(vector<string>beginWords, unordered_set<string>&wordSet, string &endWord){
vector<string>next_beginWords;
string word;
for(int i = 0; i < beginWords.size(); i++){
for(int j = 0; j < endWord.size(); j++){
word = beginWords[i];
if(word == endWord) return 1;
char tmp_c = word[j];
for(char k = 'a'; k <= 'z'; k++){
word[j] = k;
// tmp_c == k即新旧单词相同
if(!wordSet.count(word) || tmp_c == k) continue;
wordSet.erase(word);
next_beginWords.push_back(word);
}
}
}
if(next_beginWords.empty()) return 0; // 递归出口
return BFS(next_beginWords, wordSet, endWord) + 1;
}
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string>wordSet(wordList.begin(), wordList.end());
if(wordSet.count(endWord) != 1) return 0;
vector<string>beginWords{beginWord};
return BFS(beginWords, wordSet, endWord);
}
};
```
## 思路三
``` C++
class Solution {
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> wordSet(wordList.begin(), wordList.end());
if (!wordSet.count(endWord)) return 0;
queue<string> q;
q.push(beginWord);
int res = 0;
while (!q.empty()) {
for (int k = q.size(); k > 0; --k) {
string word = q.front(); q.pop();
if (word == endWord) return res + 1;
for (int i = 0; i < word.size(); ++i) {
string newWord = word;
for (char k = 'a'; k <= 'z'; ++k) {
newWord[i] = k;
if (wordSet.count(newWord) && newWord != word) {
q.push(newWord);
wordSet.erase(newWord);
}
}
}
}
++res;
}
return 0;
}
};
```