Word Ladder II
Total Accepted: 1447 Total Submissions: 17873My Submissions
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
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
Return
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
Note:
- All words have the same length.
- All words contain only lowercase alphabetic characters.
I was tormented with TLE all the morning, the following is the code, it seems not to to be better in that way:
#include<iostream>
#include<stdio.h>
#include<stack>
#include<vector>
#include<unordered_set>
#include<unordered_map>
#include<set>
#include<string>
#include<queue>
#include<map>
using namespace std;
class Solution {
public:
queue<string> fifo;
unordered_map<string,string> path;
bool cmp(string s1,string s2){
int i,count=0;
for(i=0;i<s1.length();i++){
if(s1[i]!=s2[i]){
count++;
if(count>=2)
return false;
}
}
if(count==1) return true;
else return false;
}
vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
// Note: The Solution object is instantiated only once and is reused by each test case.
while(!fifo.empty())
fifo.pop();
path.clear();
string partition="-1",front;
int flg=0;
vector<vector<string>> res;
vector<string> shortest,tmp;
unordered_set<string>::iterator it;
if(start==end){
shortest.push_back(start);
res.push_back(shortest);
return res;
}
fifo.push(start);
fifo.push(partition);
while(!fifo.empty()){
front=fifo.front();
fifo.pop();
if(front==partition){
fifo.push(partition);
if(flg||fifo.front()=="-1")
break;
}
else{
dict.erase(front);
if(cmp(front,end)){
flg=1;
shortest.clear();
tmp.clear();
tmp.push_back(end);
tmp.push_back(front);
while(front!=start){
front=path[front];
tmp.push_back(front);
}
for(int i=tmp.size()-1;i>=0;i--){
shortest.push_back(tmp[i]);
}
res.push_back(shortest);
}
else if(flg==0){
for(int i=0;i<front.length();i++){
char cur=front[i];
string last=front;
for(char ch='a';ch<='z';ch++){
if(ch!=cur){
front[i]=ch;
if(dict.find(front)!=dict.end()){
fifo.push(front);
path.insert(pair<string,string>(front,last));
}
}
}
front[i]=cur;
}
}
}
}
return res;
}
};
int main()
{
Solution s;
string start="hit";
string end="cog";
unordered_set<string> d;
// string start="hot";
// string end="dog";
d.insert("hot");
d.insert("dot");
d.insert("dog");
d.insert("lot");
d.insert("log");
vector<vector<string>> res=s.findLadders(start,end,d);
return 0;
}
However, the problem is the structure queue, it should be organized as a hash_map, because every cmp(front,end) wastes too much time, so I have to use two-layer hash_map to replace the queue. The code is :
class Solution {
public:
unordered_map<string,vector<string>> path;
unordered_set<string> layers[2];
void DFS(string curstring,string end,vector<vector<string>> &res,vector<string> &curpath){
if(curstring==end){
curpath.push_back(end);
res.push_back(curpath);
curpath.pop_back();
return;
}
if(path[curstring].size()!=0){
curpath.push_back(curstring);
for(int i=0;i<path[curstring].size();i++){
DFS(path[curstring][i],end,res,curpath);
}
curpath.pop_back();
}
}
vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
// Note: The Solution object is instantiated only once and is reused by each test case.
vector<vector<string>> res;
vector<string> shortest,tmp;
unordered_set<string>::iterator it;
layers[0].clear(); layers[1].clear(); path.clear();
int cur=0,next=1;
if(start==end){
shortest.push_back(start);
res.push_back(shortest);
return res;
}
layers[cur].insert(start);
dict.insert(end);
while(!layers[cur].empty() && layers[cur].count(end)==0 ){
for(it=layers[cur].begin();it!=layers[cur].end();it++)
dict.erase(*it);
for(it=layers[cur].begin();it!=layers[cur].end();it++){
string front=*it;
tmp.clear();
for(int i=0;i<front.length();i++){
char c=front[i];
string last=front;
for(char ch='a';ch<='z';ch++){
if(ch!=c){
front[i]=ch;
if(dict.find(front)!=dict.end()){
layers[next].insert(front);
tmp.push_back(front);
}
}
}
front[i]=c;
}
path.insert(pair<string,vector<string>>(*it,tmp));
}
cur=!cur;
next=!next;
layers[next].clear();
}
shortest.clear();
DFS(start,end,res,shortest);
return res;
}
};
Here are some mistakes I made :
- Both successors and predecessors are more than one, so map<string,vector<string>> is used to record the path instead of map<string,string>
- The string end should be added to dict, or cmp(front,end) is inevitable, which would result in TLE.
- for(it=dict.begin();it!=dict.end();it++) { dict.erase(*it) } Codes like that are totally wrong.
- Use other 25 characters to construct the next-hop graph. So the complexity is O(25n), which is faster than searching every word in dict.
- Use a DFS function to parse the path.
- This is the first time I wrote a two-layer BFS instead of a FIFO queue.
Python Version:
class Solution(object):
def DFS(self, cur, end, curPath, pathDict, paths):
if (cur == end):
curPath.append(end)
paths.append(list(curPath))
curPath.pop()
return
if (cur in pathDict):
curPath.append(cur)
for item in pathDict[cur]:
self.DFS(item, end, curPath, pathDict, paths)
curPath.pop()
def findLadders(self, beginWord, endWord, wordlist):
wordset = set(wordlist)
paths, shortest = [], []
pathDict = {}
layers = [{beginWord}, set()]
cur, next = 0, 1
wordset.add(endWord)
while (len(layers[cur]) > 0 and (endWord not in layers[cur])):
for item in layers[cur]:
wordset.discard(item)
for item in layers[cur]:
tmp = []
for i in range(len(item)):
for j in range(ord('a'), ord('z')):
newword = item[:i]+chr(j)+item[i+1:]
if (newword in wordset):
layers[next].add(newword)
tmp.append(newword)
pathDict[item] = tmp
cur, next = next, cur
layers[next].clear()
self.DFS(beginWord, endWord, [], pathDict, paths)
return paths
if __name__ == "__main__":
assert Solution().findLadders("hit", "cog", {"hot", "dot", "dog", "lot", "log"}) == [
["hit", "hot", "dot", "dog", "cog"],
["hit", "hot", "lot", "log", "cog"]
]
assert Solution().findLadders("hit", "hit", {"hot", "dot", "dog", "lot", "log"}) == [
["hit"]
]