LintCode-单词接龙II

来源:互联网 发布:网络市场监管专项行动 编辑:程序博客网 时间:2024/05/29 18:22

LintCode-单词接龙II

给出两个单词(start和end)和一个字典,找出所有从start到end的最短转换序列 比如: 每次只能改变一个字母。 变换过程中的中间单词必须在字典中出现。注意事项 所有单词具有相同的长度。 所有单词都只包含小写字母。样例给出数据如下:start = "hit"end = "cog"dict = ["hot","dot","dog","lot","log"]返回[    ["hit","hot","dot","dog","cog"],    ["hit","hot","lot","log","cog"]  ]

先直接写了个图+BFS
遍历每两个单词算different,等于1的放进邻接矩阵里面。
然后用没做优化的BFS找end

class Solution {public:    /**    * @param start, a string    * @param end, a string    * @param dict, a set of string    * @return a list of lists of string    */    struct Destination {        int num = 0;        vector<string> str;    };    struct Path {        string str;        vector<string> path;    };    map<string,bool> isPassed;    void BFS(queue<Path> &order, vector<vector<string>> &result, map<string, Destination> m, const string end) {        int num = order.size();        for (int i = 0; i < num;i++) {            Path s = order.front();            isPassed[s.str]=true;            order.pop();            if (s.str == end) {                result.push_back(s.path);            }            if (m[s.str].num != 0) {                for (auto i : m[s.str].str) {                    if(!isPassed[i])                    {                        Path p;                        p.str = i;                        p.path = s.path;                        p.path.push_back(i);                        order.push(p);                    }                }            }        }        if (!order.empty() && result.empty())            BFS(order, result, m, end);        return;    }    vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {        // write your code here        dict.insert(start);        dict.insert(end);        map<string, Destination> m;        for (auto i : dict) {            Destination d;            for (auto j : dict) {                int diff = 0;                for (int p = 0; p<i.length(); p++) {                    if (i[p] != j[p]) diff++;                }                if (diff == 1) {                    d.num++;                    d.str.push_back(j);                }            }            m[i] = d;        }        queue<Path> order;        Path s;        s.path.push_back(start);        s.str = start;        order.push(s);        vector<vector<string>> result;        BFS(order, result, m, end);        return result;    }};

过了大概七个case后超时,发现光建map就要用O(n2)。查了一下看到unordered_set的find()函数,于是改成

for (auto i : dict) {    for (int j = 0; j<i.size(); j++) {        for (int k = 0; k<26; k++) {            string tmp = i;            tmp[j] = 'a' + k;            if (dict.find(tmp)!=dict.end() && strcmp(tmp.c_str(), i.c_str())) {                m[i].num++;                m[i].str.push_back(tmp);            }        }    }}

又多过了一个case,接着是BFS超时
想一想感觉是搜索的时候队列里面会出现大量重复的单词,拖慢速度。
于是做了一个set记录每个单词的“last string”,只有没加入过的next string才能加到队列里面,保证队列里面不会有重复单词。
但这样一来就没办法直接记录path了,于是再利用刚才的set通过BFS反向找一下path,一开始作死想用栈写BFS,结果写了几十行各种出问题放弃了,直接10行递归搞定。

class Solution {public:    /**    * @param start, a string    * @param end, a string    * @param dict, a set of string    * @return a list of lists of string    */    struct Destination {        int num = 0;        vector<string> str;    };    struct Node {        unordered_set<string> last;    };    map<string, Node> node;    map<string, bool> isPassed;     vector<vector<string>> result;    void DFS(vector<string> path,string str,int count,const string& start,const int& max) {        path.push_back(str);        if (str == start) {            result.push_back(path);            reverse(result.back().begin(), result.back().end());        }        if (count == max) return;        for (auto i : node[str].last) {            DFS(path, i, count + 1, start, max);        }        return;    }    void BFS(queue<string> &order, map<string, Destination> m, const string start,const string end) {        int max=1;        while (!order.empty() && !node[end].last.size()) {            int num = order.size();            max++;            for (int i = 0; i < num; i++) {                string s = order.front();                isPassed[s] = true;                order.pop();                if (m[s].num != 0) {                    for (auto i : m[s].str) {                        if (!isPassed[i]) {                            if (node[i].last.size() == 0) {                                order.push(i);                            }                            node[i].last.insert(s);                        }                    }                }            }        }        vector<string> path;        DFS(path, end, 1, start, max);        return;    }    vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {        // write your code here        dict.insert(start);        dict.insert(end);        map<string, Destination> m;        for (auto i : dict) {            for (int j = 0; j<i.size(); j++) {                for (int k = 0; k<26; k++) {                    string tmp = i;                    tmp[j] = 'a' + k;                    if (dict.find(tmp)!=dict.end() && strcmp(tmp.c_str(), i.c_str())) {                        m[i].num++;                        m[i].str.push_back(tmp);                    }                }            }        }        queue<string> order;        order.push(start);        BFS(order, m, start,end);        return result;    }};

总共跑了500多ms,网上的代码大概300ms,贴下来有空再看

class Solution {  public:      /**       * @param start, a string       * @param end, a string       * @param dict, a set of string       * @return a list of lists of string       */      vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {          // write your code here          vector<vector<string> > result;          set<string> cur;          cur.insert(start);          set<string> next;          map<string, set<string> > parents;          unordered_set<string> unused = dict;          unused.insert(end);          visit(cur, end, next, unused, parents);          if (parents.find(end) != parents.end())          {              vector<string> buf;              generatePath(start, end, parents, buf, result);          }          return result;      }  private:      void visit(set<string> &cur, string &end, set<string> &next,                  unordered_set<string> &unused, map<string, set<string> > &parents)      {          while (parents.find(end) == parents.end() && !unused.empty())          {              next.clear();              for (set<string>::iterator it = cur.begin(); it != cur.end(); it++)              {                  string word = *it;                  string temp = *it;                  for (int i = 0; i < (*it).length(); i++)                  {                      for (char a = 'a'; a <= 'z'; a++)                      {                          temp = *it;                          if (a != word[i])                          {                              temp[i] = a;                              if (unused.find(temp) != unused.end())                              {                                  parents[temp].insert(word);                                  next.insert(temp);                              }                          }                      }                  }              }              if (next.empty())              {                  return;              }              cur = next;              for (set<string>::iterator it = next.begin(); it != next.end(); it++)              {                  unused.erase(*it);              }          }      }      void generatePath(string &start, string cur, map<string, set<string> > &parents,                     vector<string> &buf, vector<vector<string> > &result)      {          buf.insert(buf.begin(), cur);          if (cur == start)          {              result.push_back(buf);          }          else          {              for (set<string>::iterator it = parents[cur].begin(); it != parents[cur].end(); it++)              {                  generatePath(start, *it, parents, buf, result);              }          }          buf.erase(buf.begin());      }  };