Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
- Only one letter can be changed at a time
- Each intermediate word must exist in the dictionary
Example
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
Return
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
思路 2. (mapping 只存每个节点其下一层的节点!!!!)
-
HashMap
: 存每个节点其下一层的节点> mapping -
HashMap
: 存每个节点所在的层数(从0开始)distance
需要2步来处理
- BFS得到mapping (需要distance的帮助)
- 在mapping的基础上用DFS找到所有路径
class Solution {
public List> findLadders(String beginWord, String endWord, List wordList) {
List> result = new ArrayList<> ();
if (wordList == null || wordList.size () == 0 || !wordList.contains (endWord)) {
return result;
}
// all neighbors of a word
Map> mapOfWordAndNeighbors = new HashMap<> ();
// distance from the beginWord
Map distance = new HashMap<> ();
distance.put (beginWord, 0);
// convert List into Set: to avoid timeout limited
Set wordSet = new HashSet<> (wordList);
// 1. BFS to get words neighbors (only get its next layer's)
getWordNeighborsMap (wordSet, beginWord, endWord, mapOfWordAndNeighbors, distance);
if (mapOfWordAndNeighbors == null) {
return result;
}
// 2. DFS to get all paths
List combinationEntry = new ArrayList<> ();
combinationEntry.add (beginWord);
getAllPaths (beginWord, endWord, mapOfWordAndNeighbors, combinationEntry, result);
return result;
}
// using BFS to get word neighbor
// WARNING!!!!!: Don't use usedWords (HashSet<>), it's tough to handle the endWorld which has been visited
// USE DISTANCE MAP, if a neighbor candidate is not in the distance map, or it's in the distance map but it is in the same layer (has the same distance)
// then this neighbor a valid one, can put to the neighbor map
private void getWordNeighborsMap (Set wordSet,
String beginWord,
String endWord,
Map> mapOfWordAndNeighbors,
Map distance)
{
Queue currentLayer = new LinkedList<> ();
Queue nextLayer = new LinkedList<> ();
currentLayer.offer (beginWord);
while (!currentLayer.isEmpty ()) {
String current = currentLayer.poll ();
int currentDistance = distance.get (current);
for (int i = 0; i < current.length (); i++) {
for (char ch = 'a'; ch <= 'z'; ch++) {
if (current.charAt (i) == ch)
continue;
char[] tempChar = current.toCharArray ();
tempChar [i] = ch;
String tempNeighbor = String.valueOf (tempChar);
if (wordSet.contains (tempNeighbor) && (!distance.containsKey (tempNeighbor) || distance.getOrDefault (tempNeighbor, -1) == currentDistance + 1)) {
nextLayer.offer (tempNeighbor);
// 1) update the neighbor map
Set neighbors = mapOfWordAndNeighbors.getOrDefault (current, new HashSet<> ());
neighbors.add (tempNeighbor);
mapOfWordAndNeighbors.put (current, neighbors);
// 2) update the distance map
distance.put (tempNeighbor, currentDistance + 1);
}
}
}
if (currentLayer.isEmpty ()) {
currentDistance ++;
currentLayer = nextLayer;
nextLayer = new LinkedList<> ();
}
}
}
// DFS: traverse the map to get all paths
private void getAllPaths (String currentWord,
String endWord,
Map> mapOfWordAndNeighbors,
List combinationEntry,
List> result)
{
if (currentWord.equals (endWord)) {
result.add (new ArrayList<> (combinationEntry));
return;
}
for (String neighbor : mapOfWordAndNeighbors.getOrDefault (currentWord, new HashSet<> ())) {
combinationEntry.add (neighbor);
getAllPaths (neighbor, endWord, mapOfWordAndNeighbors, combinationEntry, result);
combinationEntry.remove (combinationEntry.size () - 1);
}
}
}
思路 1. (mapping 存每个节点所有邻接点)
可以将这个word看做一个graph,找到其所有最短路径,需要2个数据结构。
-
HashMap
: 存每个节点的所有邻接点> mapping -
HashMap
: 存每个节点所在的层数(从0开始)distance
需要2个函数来处理
getGraphicInfo: 填充mapping和distance (BFS算法)
public void getGraphicInfo(HashMap> mapping,
HashMap distance,
String start,
Set dict {…}
- 用queue来存储graphic的节点
- queue中每个节点都取其neighbors
a. 将该点的所有neighbors都放入mapping中对应的位置。
b. 判断该neighbor是否已在distance中,如不在则说明并未访问过- 压入queue
- 在distance中加入该neighbor的distance == curStr的distance + 1
getLadder:递归找到所有path(DFS算法)
public void getLadder(HashMap> mapping,
HashMap distance,
String start, String curStr,
Set dict,
List> result,
List path) {... }
从后往前找path
- 每次进入该函数,path.add(curStr)
- 判断是否当前curStr节点==start,相等则代表找到了目标,将path加入到result中
- 不相等,则没有找到目标,还要继续找:
遍历当前curStr的所有neighbors,如果是紧挨着的两个节点(curStr distance = neighbor distance + 1),那么就是最短的路劲上的节点,则将该neighbor传入getLadder()作为curStr,递归继续找 - 前面全部完成后,需要回朔path,每一次path都remove掉尾巴上的元素。
public class Solution {
/**
* @param start, a string
* @param end, a string
* @param dict, a set of string
* @return a list of lists of string
*/
/*
public List> findLadders(String start, String end, Set dict) {
List> result = new ArrayList<>();
if (dict == null) {
return result;
}
//存每个节点的相邻节点
HashMap> mapping = new HashMap<>();
//存每个节点所在的层数
HashMap distance = new HashMap<>();
dict.add(end);
dict.add(start);
distance.put(start, 0);
//填充了mapping, distance 2个hashmap,得到了图的所有信息
// bfs算法
getGraphicInfo(mapping, distance, start, dict);
//得到path。getLadder为DFS算法,所以path(每条路径)需从外部传入
List path = new ArrayList();
getLadder(mapping, distance, start, end, dict, result, path);
return result;
}
public void getGraphicInfo(HashMap> mapping,
HashMap distance,
String start,
Set dict) {
Queue queue = new LinkedList();
queue.add(start);
for (String str : dict) {
mapping.put(str, new ArrayList());
}
while (!queue.isEmpty()) {
String cur = queue.poll();
for (String str : getNeighbors(dict, cur)) {
//填充mapping
mapping.get(cur).add(str);
//填充distance,distance的value是str节点的前一层节点(cur节点)的层数+1
if (!distance.containsKey(str)) {
distance.put(str, distance.get(cur) + 1);
queue.add(str); //distance中没有出现过的节点才是下一层需要加继续queue的,如果已经出现过了,则不要再放进queue了,因为是以访问过的了
}
}
}
}
public void getLadder(HashMap> mapping,
HashMap distance,
String start, String curStr,
Set dict,
List> result,
List path) {
//进入函数时就加一个节点
path.add(curStr);
if (curStr.equals(start)) {
Collections.reverse(path);
result.add(new ArrayList<>(path));
Collections.reverse(path);
} else {
//找与当前节点相邻的节点,判断其是否是紧挨着的. 如果是则继续DFS算法继续找
for (String str : mapping.get(curStr)) {
if (distance.get(curStr) == distance.get(str) + 1) {
getLadder(mapping, distance, start, str, dict, result, path);
}
}
}
path.remove(path.size() - 1);
}
public List getNeighbors(Set dict, String cur) {
List result = new ArrayList();
for (int i = 0; i < cur.length(); i++) {
for (char c = 'a'; c <= 'z'; c++) {
char[] temp = cur.toCharArray();
if (cur.charAt(i) == c) {
continue;
}
temp[i] = c;
String newStr = String.valueOf(temp);
if (dict.contains(newStr)) {
result.add(newStr);
}
}
}
return result;
}
}