[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 ...
随机推荐
- java基础(14)---修饰符
修饰符:final .static.public.protected.private.default. 一.final(不能修改) 使用final修饰变量定义:该变量一旦被初始化之后就不允许再被修改. ...
- Koadic的安装和使用---http c2远控工具
Koadic的安装和使用 2017.11.26 11:02 字数 690 阅读 611评论 0喜欢 2 概述 Koadic是DEFCON分型出来的一个后渗透工具,主要通过vbscript.jscr ...
- 使用CefSharp在C#访问网站,支持x86和x64
早已久仰CefSharp大名,今日才得以实践,我其实想用CefSharp来访问网站页面,然后抓取html源代码进行分析,如果使用自带的WebBrowser控件,可能会出现一些不兼容js的错误. Cef ...
- 动态创建自绘的CListBox注意事项
Create(WS_VISIBLE|WS_CHILD|LBS_NOTIFY|LBS_OWNERDRAWFIXED|LBS_HASSTRINGS|LBS_NOINTEGRALHEIGHT ,rcWnd, ...
- 堆内存腐败异常(STATUS_HEAP_CORRUPTION---0xC0000374)
什么是内存腐败 当堆内存位置的内容由于编程行为而被修改,超出了原始程序构造的意图时,计算机程序就会发生内存腐败,也可以叫内存破坏:这被称为违反内存安全.内存腐败的最可能原因是编程错误.当腐败的内存内容 ...
- s3git 使用git 管理云存储
使用s3git 我们可以方便的基于git协议进行s3存储数据的版本管理,同时也提供了一个方便的golang 包, 我们可以集成到我们的应用中,但是有一点,目前已经没有再更新过了,但是设计理论很不错,实 ...
- less简介及其编译原理
一.less环境安装 ①首先需要在电脑上安装nodejs,一般会内置npm,利用以下命令可以检测: ②利用npm在线安装less,运行 npm install –g less ③查看是否安装成功,L ...
- cyyz : Day 1 数论整理
声明:感谢修改这篇博客的dsr Day 1 先说一下上午的听课吧,哎~,简直了,简直(⊙o⊙)…咋说呢,引人入胜???No! 是昏昏欲睡好吧...一点听课欲都没有(强撑....),一上午停下来简直怀疑 ...
- 【UVA11987】Almost Union-Find
题目链接 题目就告诉我们要用并查集了,操作1和3用裸的带权并查集就行了, 操作2相当于将p结点从当前树中删除,再插入到q的树中,直接删除的话比较麻烦,不妨把它的"尸体"留在原来的地 ...
- Android Studio一直显示Building“project name”Gradle project info问题详解
关注我,每天都有优质技术文章推送,工作,学习累了的时候放松一下自己. 本篇文章同步微信公众号 欢迎大家关注我的微信公众号:「醉翁猫咪」 Android Studio一直显示 Building&quo ...