[LeetCode] 126. Word Ladder II 词语阶梯 II
Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:
- Only one letter can be changed at a time
- Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
Note:
- Return an empty list if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
- You may assume no duplicates in the word list.
- You may assume beginWord and endWord are non-empty and are not the same.
Example 1:
Input:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]
Output:
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
Example 2:
Input:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
Output: []
Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
给一个单词字典,把一个起始单词变为结束单词,每次只能变化一个字符,而且变化的中间词都在字典中,找出所有最短路径变换的组合。127. Word Ladder的拓展,127题是让返回最短路径的长度。
解法:BFS,这题难度和代码量都很大。
因为要记录路径, 所以要为每一个结点记录一下父结点, 这样最后的时候我们就从终点开始一个个往前找其父结点, 直到找到起始点, 然后翻转一下加入结果集合中即可.
大概过程差不多, 但是有点不同的是当将字典中的一个字符串删除的时候在另一条路径上可能还会用到这个字符. 也就是像这样:
A -> C -> D, B->C->D
他们都会经过C, 并且两个都是最短的路径, 在A的时候搜索到C, 并且将C从字典中删除, 当B在搜索与其距离为1的字符串时, C已经不在字典中了, 那么怎么办呢? 我们设置一个hash表用来存储一个字符串的父结点集合, 这样C不在字典中再去查hash表看C是否在hash表中, 如果在的话并且C的父结点层次和B一样, 那么就将B也加入到C的父结点结合中去. 可以知道, 一个字符串的父结点集合的距离起点的距离必然是相等的, 也就是说他们都是最短距离.
最后遍历完所有的点之后, 再用DFS从终点往前找出所有集合即可.
Java:
public class Solution {
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
HashSet<String> dict = new HashSet<>(wordList);
HashMap<String, Integer> distance = new HashMap<>();
HashMap<String, List<String>> adj = new HashMap<>();
List<List<String>> result = new ArrayList<>();
List<String> path = new ArrayList<>();
dict.add(beginWord);
bfs(beginWord, endWord, dict, adj, distance);
path.add(beginWord);
dfs(beginWord, endWord, result, path, dict, adj, distance);
return result;
}
public List<String> getNeighbor(String word, HashSet<String> dict) {
List<String> result = new ArrayList<>();
char[] arr = word.toCharArray();
for (char c = 'a'; c <= 'z'; c++) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == c) {
continue;
}
char ch = arr[i];
arr[i] = c;
if (dict.contains(String.valueOf(arr))) {
result.add(String.valueOf(arr));
}
arr[i] = ch;
}
}
return result;
}
public void bfs(String start,
String end,
HashSet<String> dict,
HashMap<String, List<String>> adj,
HashMap<String, Integer> distance) {
for (String word : dict) {
adj.put(word, new ArrayList<String>());
}
Queue<String> queue = new LinkedList<>();
queue.offer(start);
distance.put(start, 0);
while (!queue.isEmpty()) {
String curr = queue.poll();
int level = distance.get(curr);
List<String> neighbor = getNeighbor(curr, dict);
for (String nei : neighbor) {
adj.get(curr).add(nei);
if (!distance.containsKey(nei)) {
distance.put(nei, level + 1);
if (!end.equals(nei)) {
queue.offer(nei);
}
}
}
}
}
public void dfs(String curr,
String end,
List<List<String>> result,
List<String> path,
HashSet<String> dict,
HashMap<String, List<String>> adj,
HashMap<String, Integer> distance) {
if (curr.equals(end)) {
result.add(new ArrayList<>(path));
return;
}
for (String nei : adj.get(curr)) {
path.add(nei);
if (distance.containsKey(nei) && distance.get(nei) == distance.get(curr) + 1) {
dfs(nei, end, result, path, dict, adj, distance);
}
path.remove(path.size() - 1);
}
}
}
Java:
class WordNode{
String word;
int numSteps;
WordNode pre;
public WordNode(String word, int numSteps, WordNode pre){
this.word = word;
this.numSteps = numSteps;
this.pre = pre;
}
}
public class Solution {
public List<List<String>> findLadders(String start, String end, Set<String> dict) {
List<List<String>> result = new ArrayList<List<String>>();
LinkedList<WordNode> queue = new LinkedList<WordNode>();
queue.add(new WordNode(start, 1, null));
dict.add(end);
int minStep = 0;
HashSet<String> visited = new HashSet<String>();
HashSet<String> unvisited = new HashSet<String>();
unvisited.addAll(dict);
int preNumSteps = 0;
while(!queue.isEmpty()){
WordNode top = queue.remove();
String word = top.word;
int currNumSteps = top.numSteps;
if(word.equals(end)){
if(minStep == 0){
minStep = top.numSteps;
}
if(top.numSteps == minStep && minStep !=0){
//nothing
ArrayList<String> t = new ArrayList<String>();
t.add(top.word);
while(top.pre !=null){
t.add(0, top.pre.word);
top = top.pre;
}
result.add(t);
continue;
}
}
if(preNumSteps < currNumSteps){
unvisited.removeAll(visited);
}
preNumSteps = currNumSteps;
char[] arr = word.toCharArray();
for(int i=0; i<arr.length; i++){
for(char c='a'; c<='z'; c++){
char temp = arr[i];
if(arr[i]!=c){
arr[i]=c;
}
String newWord = new String(arr);
if(unvisited.contains(newWord)){
queue.add(new WordNode(newWord, top.numSteps+1, top));
visited.add(newWord);
}
arr[i]=temp;
}
}
}
return result;
}
}
Python:
class Solution:
# @param start, a string
# @param end, a string
# @param dict, a set of string
# @return an integer
def findLadders(self, start, end, dict):
dict.add(start)
dict.add(end) result, cur, visited, found, trace = [], [start], set([start]), False, {word: [] for word in dict} while cur and not found:
for word in cur:
visited.add(word) next = set()
for word in cur:
for i in xrange(len(word)):
for j in 'abcdefghijklmnopqrstuvwxyz':
candidate = word[:i] + j + word[i + 1:]
if candidate not in visited and candidate in dict:
if candidate == end:
found = True
next.add(candidate)
trace[candidate].append(word)
cur = next if found:
self.backtrack(result, trace, [], end) return result def backtrack(self, result, trace, path, word):
if not trace[word]:
result.append([word] + path)
else:
for prev in trace[word]:
self.backtrack(result, trace, [word] + path, prev)
C++:
class Solution {
public:
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
vector<vector<string>> res;
unordered_set<string> dict(wordList.begin(), wordList.end());
vector<string> p{beginWord};
queue<vector<string>> paths;
paths.push(p);
int level = 1, minLevel = INT_MAX;
unordered_set<string> words;
while (!paths.empty()) {
auto t = paths.front(); paths.pop();
if (t.size() > level) {
for (string w : words) dict.erase(w);
words.clear();
level = t.size();
if (level > minLevel) break;
}
string last = t.back();
for (int i = 0; i < last.size(); ++i) {
string newLast = last;
for (char ch = 'a'; ch <= 'z'; ++ch) {
newLast[i] = ch;
if (!dict.count(newLast)) continue;
words.insert(newLast);
vector<string> nextPath = t;
nextPath.push_back(newLast);
if (newLast == endWord) {
res.push_back(nextPath);
minLevel = level;
} else paths.push(nextPath);
}
}
}
return res;
}
};
类似题目:
[LeetCode] 127. Word Ladder 单词阶梯
All LeetCode Questions List 题目汇总
[LeetCode] 126. Word Ladder II 词语阶梯 II的更多相关文章
- Java for LeetCode 126 Word Ladder II 【HARD】
Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from ...
- LeetCode 126. Word Ladder II 单词接龙 II(C++/Java)
题目: Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transfo ...
- [LeetCode] 126. Word Ladder II 词语阶梯之二
Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformat ...
- leetcode 126. Word Ladder II ----- java
Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformat ...
- Leetcode#126 Word Ladder II
原题地址 既然是求最短路径,可以考虑动归或广搜.这道题对字典直接进行动归是不现实的,因为字典里的单词非常多.只能选择广搜了. 思路也非常直观,从start或end开始,不断加入所有可到达的单词,直到最 ...
- leetcode@ [126] Word Ladder II (BFS + 层次遍历 + DFS)
https://leetcode.com/problems/word-ladder-ii/ Given two words (beginWord and endWord), and a diction ...
- [LeetCode] 127. Word Ladder 单词阶梯
Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest t ...
- leetcode 127. Word Ladder、126. Word Ladder II
127. Word Ladder 这道题使用bfs来解决,每次将满足要求的变换单词加入队列中. wordSet用来记录当前词典中的单词,做一个单词变换生成一个新单词,都需要判断这个单词是否在词典中,不 ...
- 126. Word Ladder II(hard)
126. Word Ladder II 题目 Given two words (beginWord and endWord), and a dictionary's word list, find a ...
随机推荐
- 使用Arduino开发板连接干簧管(Reed Switch)的方法
在现实生活中,干簧管(Reed Switch)有许多重要的应用,如磁性门开关.笔记本电脑.智能手机等.在本篇文章中,我们将了解一些干簧管的知识,并介绍如何使用Arduino开发板连接干簧管. 干簧管( ...
- python测试开发django-58.MySQL server has gone away错误的解决办法
前言 使用django执行sql相关操作的时候,出现一个"MySQL server has gone away"错误,后来查了下是sql执行过程中,导入的文件较大时候,会出现这个异 ...
- Java实现行列式计算
前天我看线代书,看到行列式,发现是个递归的式子,恰巧又正在学java,产生写程序实现的想法.写了两个小时,觉得实现了,写了个行列式放进去测试,我放的是 这个行列式,经过程序计算后发现结果是0.我以为我 ...
- 如何让VS像CB一样使用
之前用VS,先是完成了GLUT库下的opengl使用: 然后得知GLUT有些过时,又按照教程接触了GLFW库下,反正对我来说是有些复杂. 今天正式试一试用VS来写ACM的题目,发现不能定义string ...
- 《团队作业第三、四周》五阿哥小组Scrum 冲刺阶段---Day3
<团队作业第三.四周>五阿哥小组Scrum 冲刺阶段---Day3 一.项目燃尽图 二.项目进展 20182310周烔今日进展: 主要任务一览:界面布局的设计 20182330魏冰妍今日进 ...
- NOI2018游记【一年后的回忆】
今天是2019年9月6日,我坐在大学的宿舍里,同样敲着键盘,在一年前充满回忆与汗水的博客上,又一次地回忆往事. 那是2018年的7月,我停了三个月的课,攥着一张thusc的安慰约,放手在OI的生涯最后 ...
- LeetCode 785. Is Graph Bipartite?
原题链接在这里:https://leetcode.com/problems/is-graph-bipartite/ 题目: Given an undirected graph, return true ...
- H5中实现加载更多的逻辑及代码执行。
H5中加载更多的逻辑总结: 1.首先,需要三个底部的提示,分别是“加载中”.“--我是有底线的--”.“暂时没有记录”,当然,这三句话根据不同的项目,可以自定义.具体代码例子如下: <div c ...
- learning java 读写其他进程的数据
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public ...
- 关于System.AccessViolationException异常
什么是AccessViolationException 试图读写受保护内存时引发的异常. 继承 Object Exception SystemException AccessViolationExce ...