Solution 1
本体要求最小路径,因此BFS没跑,但是要求递归所有最小结果,可能还是需要DFS的,但是当前版本的实现不需要DFS。利用前几个题的分层BFS,以路径为节点可以完成搜索。使用哈希表来优化存在判定的时间。
此外,一个题解中使用了双向BFS来优化搜索空间,整个思路就是交替地从两个单词展开并找到相遇的时刻,此时刻下相遇位置各自搜索路径的结合即为最优方案:详细通俗的思路分析,多解法 - 单词接龙 II - 力扣(LeetCode) (leetcode-cn.com)
我的实现慢的有点过分,但是目前以学习为主,优化留给后面
- 时间复杂度: O ( N d ) O(N^d) O(Nd),其中 N N N为wordList的长度, d d d为编辑距离,最坏的搜索范围就是每一层都是全展开,实际会有大量剪枝
- 空间复杂度: O ( d N d ) O(dN^d) O(dNd),其中 N N N为wordList的长度, d d d为编辑距离,最坏的搜索范围就是每一层都是全展开,保存的是路径,因此最后一层的每个节点大小都应为 d d d,实际会有大量剪枝
class Solution {
public:
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
vector<vector<string>> ans;
// 序列中必须要有endWord
unordered_set<string> words = {wordList.begin(), wordList.end()};
if (words.find(endWord) == words.end()) {
return ans;
}
this->bfs(beginWord, endWord, words, ans);
return ans;
}
private:
void bfs(string & beginWord, string & endWord, unordered_set<string> & words, vector<vector<string>> & ans) {
queue<vector<string>> q;
vector<string> path;
path.push_back(beginWord);
q.push(path);
bool flag = false; // 是否向下层搜索
unordered_set<string> visited;
while (!q.empty()) {
// 分层bfs
int size = q.size();
vector<string> tempVisited;
while (size--) {
auto temp = q.front();
q.pop();
auto tempWord = temp.back();
auto mods = this->getMods(tempWord, words);
for (auto mod: mods) {
if (visited.find(mod) == visited.end()) {
// 得是之前没出现过的单词
temp.push_back(mod);
if (mod == endWord) {
// 正好找到endWord,搜索完当前层后终止
flag = true;
ans.push_back(temp);
} else {
// 不是,保存结果路径到队列中
q.push(temp);
tempVisited.push_back(mod);
}
temp.pop_back();
}
}
}
if (flag) { break; }
visited.insert(tempVisited.begin(), tempVisited.end());
}
}
vector<string> getMods (string word, unordered_set<string> & words) {
vector<string> mods;
for (int index = 0; index < word.size(); ++index) {
auto temp = word[index];
for (char ch = 'a'; ch <= 'z'; ++ch) {
if (temp != ch) {
word[index] = ch;
if (words.find(word) != words.end()) {
mods.push_back(word);
}
}
}
word[index] = temp;
}
return mods;
}
};
Solution 2
Solution 1的Python实现
class Solution:
def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
def bfs() -> None :
nonlocal beginWord, endWord, wordList, ans
q = deque()
path = list()
path.append(beginWord)
q.append(path)
flag = False
visited = set()
while len(q) > 0:
size = len(q)
tempVisited = list()
while size > 0:
temp = q.popleft()
tempWord = temp[-1]
mods = getMods(tempWord)
for mod in mods:
if mod not in visited:
temp.append(mod)
if mod == endWord:
flag = True
ans.append(copy.deepcopy(temp))
else:
q.append(copy.deepcopy(temp))
tempVisited.append(mod)
temp.pop()
size -= 1
if flag: break
visited.update(tempVisited)
def getMods(word: str) -> List[str]:
nonlocal wordList
mods = list()
word_list = list(word)
for i in range(len(word)):
temp = word_list[i]
for ch in string.ascii_lowercase:
word_list[i] = ch
newWord = ''.join(word_list)
if newWord in wordList:
mods.append(newWord)
word_list[i] = temp
return mods
ans = list()
if endWord not in wordList: return ans
bfs()
return ans