leetcode-Word Ladder II

Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:

  1. Only one letter can be changed at a time
  2. 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
题意:给出起始词start和目的词end,以及字典dict,要求找到所有从start到end的最短路径,满足:
(1)路径上每个词都在dict中
(2)路径上相邻的词只能相差一个字母
给出的所有词长度相同,均由小写字母构成。
分析:比较难得一道图论题。
首先,基本思想是用BFS搜索可行路径,如果想要更快可以用双向BFS。然后用DFS记录路径。
其次,在每次搜索时,如何搜索下一步的单词,一开始我直接遍历的字典找和当前词距离为1的,这样显然会超时。。后来看到别人的方法为遍历单词的每个位置,枚举26个字母的所有情况,找这个新词是否在字典中出现,搜索空间只有L*26,L为单词长度。
在搜索可行路径时,要注意:(1)之前搜索过得词不能再搜索到,否则会成环,处理方法是每次BFS新的一层时,将上一层的词从dict字典删除。
(2)一次BFS之后,搜索到的所有新词要去重,因为BFS层与层之间存在多对多关系,所有不去重会造成搜索空间很大,内存溢出。这里用两个unordered_set存储上一层的词和当前层搜索到的词
最后,用一个unordered_map<string,vector<string>> 记录路径,每个元素的value记录key的前趋词表,记录前趋才能去除冗余,若记录后继词表,会有很多不可行路径。BFS后,用DFS遍历这个map记录结果。
代码:
class Solution {
private:
    int caldis(string x,string y)
    {
        int dis = 0;
        for(int i=0; i<x.length(); i++)
            if(x[i]!=y[i])
                dis++;
        return dis;
    }
    
    void dfs(unordered_map<string,vector<string> > &mp,string cur,vector<string> &now,vector<vector<string> > &ans)
    {
        now.push_back(cur);
        if(mp[cur].size()==0)
        {
            vector<string> tmp(now);
            reverse(tmp.begin(),tmp.end());
            ans.push_back(tmp);
            now.pop_back();
            return;
        }
        for(int i=0; i<mp[cur].size(); i++)
        {
            dfs(mp,mp[cur][i],now,ans);
        }
        now.pop_back();
    }
    
public:
    vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
        vector<string> now;
        vector<vector<string> > ans;
        if(start==end)
        {
            now.push_back(end);
            ans.push_back(now);
            return ans;
        }
        
        unordered_set<string> qu[2];
        unordered_map<string,vector<string> > mp;
        for(auto it=dict.begin(); it!=dict.end(); it++)
        {
            mp[*it] = vector<string>();
        }
        qu[0].insert(start);
        int i=0;
        bool isdone = false;
        while(!qu[i].empty())
        {
            i = 1-i;
            qu[i].clear();
            
            for(auto it=qu[1-i].begin(); it!=qu[1-i].end(); it++)
            {
                if(caldis(*it,end)==1)
                {
                    isdone = true;
                    mp[end].push_back(*it);
                }
                dict.erase(*it);
            }
            if(isdone) break;
            
            for(auto it=qu[1-i].begin(); it!=qu[1-i].end(); it++)
            {
                string cur = *it;
                for(int j=0; j<cur.size(); j++)
                {
                    for(char ch='a'; ch<='z'; ch++)
                    {
                        string tmp = cur;
                        tmp[j] = ch;
                        if(dict.find(tmp)!=dict.end())
                        {
                            mp[tmp].push_back(cur);
                            qu[i].insert(tmp);
                        }
                    }
                }
            }
        }
        
        ans.clear();
        now.clear();
        if(!isdone) return ans;
        dfs(mp,end,now,ans);
        return ans;
    }
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值