LintCode-单词接龙II

本文介绍了在LintCode中解决单词接龙问题的方法,首先通过图和BFS建立邻接矩阵,然后优化BFS过程,避免队列中的重复单词,最后通过反向BFS找到路径,通过递归实现。尽管最终运行时间较长,但通过这些优化已显著提高了效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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(n 2 )。查了一下看到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());  
    }  
};  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值