[Leetcode 126] Word Ladder II

  • Question
    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.
    For example,

Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]
Return
  [
    ["hit","hot","dot","dog","cog"],
    ["hit","hot","lot","log","cog"]
  ]
  • 思路
    这个题是一个无向图查找所有的最短路径的题。
    我首先是想到了用深度搜索(DFS)去做。但是写出的代码只能通过 wordList 比较小的情况,wordList大的时候总是报 Time Limit Exceed错误。我在vs上调试时 发现原因是 递归调用层次太深,程序就死了。
    后面我采用空间换时间策略, 用BFS算法重写, 通过了。

    另外有一种思路是 BFS+DFS. 即先用BFS 把无向图变成有向图, 把每个节点的父节点和子节点保存下来,再用DFS 去查找最短路径,有兴趣的可以在网上找一下

-代码如下:

class Solution {
public:
/* compare() 是比较string a 和 b 有几个字母不同 */
bool compare(string &a, string &b) {
    int cnt = 0;
    if (a.size() == b.size())
        for (int i = 0; i < a.size(); ++i) {
            if (a[i] != b[i]) {
                ++cnt;
                if (cnt > 1) break;
            }
        }
    return cnt == 1;
}
/*
 build() 找出节点 word 的所有相邻节点,(即找出与 word 只有一个字符不同的所有 string), 保存到   set<string> 中
*/
set<string> build(string word, vector<string> &wordList) {
    set<string> ret;
    for (auto a : wordList) {
        if (compare(a, word)) {
            ret.insert(a);
        }
    }
    return ret;
}


vector<vector<string>> findLadders(string beginWord, string endWord, vector<string> wordList) {
    vector<vector<string>> ret;  // 返回
    if ((find(wordList.begin(), wordList.end(), endWord)) == wordList.end()) return ret;
    map<string, set<string>> str_set;   
    queue<string> s;
    //记录从初始节点beginWord到当前节点的最短路径的长度
    map<string, int> flash;  
//记录从初始节点beginWord到当前节点的所有最短路径的,这些路径保存到set<vector<string>>中
    map<string, set<vector<string>>> route; 
    //建立无向图,保存到 str_set 中
    for (auto a : wordList) {
        str_set[a] = build(a, wordList);
        flash[a] = 0;
    }
    //将beginWord加入到图中,如果beginWord本身在图中也不会有影响
    str_set[beginWord] = build(beginWord, wordList);
    flash[beginWord] = 1;  //beginWord 到beginWord 路径长度为1,相应路径保存到route[beginWord]中
    route[beginWord].insert({ beginWord });
    s.push(beginWord);
    while (!s.empty()) {
        string val = s.front();
        for (auto &a : str_set[val]) {
        //遍历val的所有邻接点, flash[a] == 0 表示该节点该节点 第一次被访问,
        //flash[a] >= (flash[val] + 1) 表示发现比当前找到的路径的长度相等或者更短的新路径,要更新
            if (flash[a] == 0 || flash[a] >= (flash[val] + 1)) {

                //找到更短的路径,则把先前保存的路径清除
                if (flash[a] > flash[val] + 1){
                    route[a].clear();
                    flash[a] = flash[val] + 1; 
                }
                int temp = 1;
                for (auto b : route[val]) {
                    b.push_back(a);
        //如果该路径已经保存在已有路径中,是重复访问,跳出,temp置0
                    if (route[a].find(b) != route[a].end()) 
                    {
                        temp = 0;
                        break;
                    }
                    route[a].insert(b);
                }
                //更新后的节点要重新加入到 队列中
                if (temp)
                    s.push(a);
            }
            if (a == endWord) break;
        }
        s.pop();
    }
    for (auto a : route[endWord])
        ret.push_back(a);
    return ret;
}
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值