第四周:[leetcode] 126. Word Ladder II

来源:互联网 发布:空降什么意思网络 编辑:程序博客网 时间:2024/05/22 08:28

题目链接:链接
题目描述:在wordList中寻找从beginWord到endWord的最短转换序列,要求每次转化只能变换一个字符。

Given:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,”dot”,”dog”,”lot”,”log”,”cog”]

Return
[
[“hit”,”hot”,”dot”,”dog”,”cog”],
[“hit”,”hot”,”lot”,”log”,”cog”]
]

解题思路:一开始以先解题目,后考虑空间、效率的目的,没有过多考虑,写了个DFS + 截枝的思路,算法实现较为简单,但效率过低,在跑list.size() > 100的测试用例时TLE,Solution1代码如下:

Solution1://判断是否能从pre转化为curbool canChange(string pre, string cur, vector<string>& sub){    for(int i = 0; i < sub.size(); i++){        if(cur == sub[i])return false;    }    //有一个字符不同即可以转化    int count = 0;    for(int i = 0; i < pre.length(); i++){        if(pre[i] != cur[i])count++;        if(count > 1)return false;    }    return count == 1;}void findLadder(string end, vector<string>& list, vector<vector<string>>& res, vector<string>& sub){    string cur = sub.back();    //能转换到wordEnd则加入result容器    if(cur == end){        if(res.empty() || res[0].size() == sub.size())            res.push_back(sub);        else if(res[0].size() > sub.size()){            res.clear();            res.push_back(sub);        }        return;    }    //如果转换列表的长度大于当前res容器存储列表的长度,则返回,实现截枝    if(res.size() != 0 && res[0].size() <= sub.size())return;    //递归查找    for(int i = 0; i < list.size(); i++){        if(canChange(cur, list[i], sub)){            sub.push_back(list[i]);            findLadder(end, list, res, sub);            sub.pop_back();        }    }}vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {    vector<vector<string>> res;    vector<string> sub;    sub.push_back(beginWord);    findLadder(endWord, wordList, res, sub);    return res;}

算法分析:
1. 编写代码时就注意到效率最低肯定在递归查找,每次递归都进行O(n)时间寻找,效率极低,可建立unordered_map映射,保存所有已搜寻过的可转换序列加入列表,先从列表查找;
2. canChange函数判断是否能从pre转化为cur,vector数据结构的遍历也为O(n1)时间;可用红黑树实现的unordered_set数据结构,查找效率为O(log(n1));
3. 算法本身性质问题,深度搜索不保证第一次搜寻的就是最短序列,广度优先搜寻所有最优解更合适。
针对以上问题,进行改进:现广度优先搜索生成树,后进行路径生成,得解!但是,在更大更大更大数量的测试下还是差在时间问题!!!再次思考数据结构的问题···通过漫长漫长的思考以及网上的学习,发现可进行以下思路进行改进:
1.运用两个unordered_set数据结构,保存生成树前一高度与当前高度的字符串,交替变换,可将已在树中的string从list中删除,保证父树不重复出现在子树节点中;如(1)a->b,b->c,(2)a->c的情况,当广度搜寻完c时,把c删除,截去情况(1);
2.判断子节点方面,逐位置改变父节点的字符进行判断,建树效率为str.length*26*log(n)(平衡二叉树查找),而Solution1对list遍历进行查找,其效率为stri.length*n;
奋战近1.5天,Solution2解题如下(176ms AC):
网上见有88ms,56msAC的方法,休息片刻,再继续学习~总而言之,编程量较大的题目思考收获挺多的~

void findPath(string now, string end, vector<string>& sub,              unordered_map<string, vector<string>>& path, vector<vector<string>>& res){    if(now == end){        sub.push_back(now);        vector<string> t = sub;        reverse(t.begin(), t.end());        res.push_back(t);        sub.pop_back();        return;    }    for(int i = 0; i < path[now].size(); i++){        sub.push_back(now);        findPath(path[now][i], end, sub, path, res);        sub.pop_back();    }}vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {    vector<vector<string>> res;    unordered_set<string> list(wordList.begin(), wordList.end());    unordered_map<string, vector<string>> path;    vector<unordered_set<string>> layer(2);    int cur = 0;    int pre = 1;    list.insert(beginWord);    layer[cur].insert(beginWord);    while(true){        swap(cur, pre);        layer[cur].clear();        for(unordered_set<string>::iterator iter = layer[pre].begin(); iter != layer[pre].end(); iter++){            list.erase(*iter);            string t = *iter;            for(int i = 0; i < (*iter).size(); i++){                string word = *iter;                int stop = word[i] - 'a';                for(int j = (stop + 1)%26; j != stop; j = (j+1) % 26){                    word[i] = j + 'a';                    //layer[pre].find(word) == layer[pre].end()除去寻找过程中已保存在pre的情况                    if(list.find(word) != list.end() && layer[pre].find(word) == layer[pre].end()){                        layer[cur].insert(word);                        path[word].push_back(*iter);                    }                }            }        }        if(layer[cur].size() == 0){            return res;        }        if(layer[cur].find(endWord) != layer[cur].end()){            break;        }    }    vector<string> sub;    //从endWord到beginWord查找    findPath(endWord, beginWord, sub, path, res);    return res;}
0 0
原创粉丝点击