[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 ...
随机推荐
- Cisco网络模拟器踩坑记录
1.在我们新建一个拓扑图的时候,选择设备之间的连线种类有时会导致线路不通的情况(两个端口上为红色点)这时候建议拆除这条线后选择闪电标记 的万能线帮助我们自动创建连线(这时就能根据它显示的线条种类得知应 ...
- MySQL的增、删、改、查
数据库的常用命令以及作用 用法 作用 CREATE database 数据库名称. 创建新的数据库 DESCRIBE 表单名称; 描述表单 UPDATE 表单名称 SET attribute=新值 W ...
- 【http】认识HTTP
HTTP基础概念 我们学计算机网络的时候就知道,我们把计算机网络分层了5层,一般我们现在用的都是TCP/IP这么一个分层结构. 虽然官方的是ISO 提出的7层结构,但是仅仅是理论基础,在实际上大多人都 ...
- memoryCache 和 diskCache 的相关总结
一.缓存位置 在浏览器开发者工具的 Network 的 Size 栏会出现的三种情况: from Service Worker from memory cache from disk cache 真正 ...
- django-改写manage类-objects
user/models.py中 class AddressManage(models.Manager): '''地址模型管理类''' def get_default_addr(self, user): ...
- 六.深浅copy
先问问大家,什么是拷贝?拷贝是音译的词,其实他是从copy这个英文单词音译过来的,那什么是copy? copy其实就是复制一份,也就是所谓的抄一份.深浅copy其实就是完全复制一份,和部分复制一份的意 ...
- 查vue版本号
在项目中,找到package.json文件夹 找"dependencies"然后就可以看到你装的vue的版本了.
- 按值传递与按值引用详解(java版)
http://blog.csdn.net/zzp_403184692/article/details/8184751
- python基础代码
from heapq import *; from collections import *; import random as rd; import operator as op; import r ...
- 38861cba61c66739c1452c3a71e39852.ttf net::ERR_ABORTED 404 (Not Found)
error: http://localhost:63342/clappr-dev/js/38861cba61c66739c1452c3a71e39852.ttf net::ERR_ABORTED 40 ...