LeetCode - Word Ladder II 题解

本文介绍了如何使用广度优先搜索(BFS)和深度优先搜索(DFS)来找到从起点到终点的所有最短路径,并优化了内存使用。讨论了在解决此类问题时的挑战和改进策略。

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

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.
这次是要打印所有道路
1.一开始用一个queue<vector<string> > 记录每一步的路径,超内存
class Solution {
public:
    vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
        minn = 2147483647;
        queue<string> Q;
        queue<vector<string> > disQ;
        Q.push(start);
        disQ.push(vector<string> {start});
        while(!Q.empty()){
            string head = Q.front();
            Q.pop();
            vector<string> headDis = disQ.front();
            //printVector<string>(headDis);
            int ladderSize = headDis.size();
            if(ladderSize + 2 > minn){
                return ans;
            }
            disQ.pop();
            for(unsigned int l = 0; l < head.length(); ++l){
                string str = head;
                for(char ch = 'a'; ch <= 'z' ; ++ch)
                    if(ch != head[l]){
                        str[l] = ch;
                        if(str == end){
                            minn = min(minn, ladderSize + 2);
                            headDis.push_back(end);
                            ans.push_back(headDis);
                            headDis.pop_back();
                        }
                        else if(dict.find(str) != dict.end()){
                            bool flag = true;
                            for(auto word : headDis){
                                if(word == str){
                                    flag = false;
                                    break;
                                }
                            }
                            if(flag){
                                Q.push(str);
                                headDis.push_back(str);
                                disQ.push(headDis);
                                headDis.pop_back();
                            }
                        }
                    }
            }
        }

        return ans;
    }
private:
    int minn;
    vector<vector<string> > ans;
};

2.后来想到只记录队列中的前驱节点,还是超内存= =
class Solution {
public:
    vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
        minn = 2147483647;
        vector<string> Q;
        vector<int> pre;
        queue<int> dis;
        Q.push_back(start);
        pre.push_back(-1);
        dis.push(1);
        int headPtr = 0;
        while(Q.size() > headPtr){
            string head = Q[headPtr];
            int ladderSize = dis.front();
            dis.pop();
            if(ladderSize + 1 > minn){
                break;
            }
            for(unsigned int l = 0; l < head.length(); ++l){
                string str = head;
                for(char ch = 'a'; ch <= 'z' ; ++ch)
                    if(ch != head[l]){
                        str[l] = ch;
                        if(str == end){
                            minn = min(minn, ladderSize + 1);
                            vector<string> route;
                            int k = headPtr;
                            while(k != -1){
                                route.insert(route.begin(), Q[k]);
                                k = pre[k];
                            }
                            route.push_back(end);
                            ans.push_back(route);
                        }
                        else if(dict.find(str) != dict.end()){
                            bool flag = true;
                            int k = headPtr;
                            while(k != -1){
                                if(Q[k] == str){
                                    flag = false;
                                    break;
                                }
                                k = pre[k];
                            }
                            if(flag){
                                Q.push_back(str);
                                pre.push_back(headPtr);
                                dis.push(ladderSize + 1);
                            }
                        }
                    }
            }
            ++headPtr;
        }
        return ans;
    }
private:
    int minn;
    vector<vector<string> > ans;
};

3.所以考虑先把最小路程用bfs求出来,再dfs产生所有路径。其中还有一些可以优化的点,具体可以参考 http://www.tuicool.com/articles/eaQNNr
最后但是如果用bfs产生邻接表(注释中的)会比用上面文章中的方法慢一倍。。暂时没有搞明白为什么,初步猜测是hash的unordered_map查询消耗了时间。

class Solution {
public:
    vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
        minn = 2147483647;
        calcMinRoute(start, end, dict);
        vector<string> ladder{end};
        calcAllRoutes(start, end, ladder);
        return ans;
    }
private:
    int minn;
    vector<vector<string> > ans;
    unordered_map<string, int> level;
    unordered_map<string, unordered_set<string> > adj;
   /* void calcMinRoute(string start, string end, unordered_set<string> &dict){
        dict.insert(end);
        queue<string> Q;
        Q.push(start);
        level[start] = 1;
        while(!Q.empty()){
            string head = Q.front();
            Q.pop();
            if(minn < level[head] + 1){
                return;
            }
            for(unsigned int l = 0; l < head.length(); ++l){
                string str = head;
                for(char ch = 'a'; ch <= 'z' ; ++ch)
                    if(ch != head[l]){
                        str[l] = ch;
                        if(dict.find(str) != dict.end() && (level[str] == 0 || level[str] == level[head] + 1)){
                   if(level[str] == 0){
<span style="white-space:pre">				</span>Q.push(str);
                     level[str] = level[head] + 1;
                   }
                            adj[str].insert(head);
                        }
                        if(str == end){
                            minn = level[head] + 1;
                        }
                    }
            }
        }
        return;
    }
    */
    void calcMinRoute(string start, string end, unordered_set<string> &dict){
        unordered_set<string> current_level;
        unordered_set<string> next_level;
        unordered_set<string> unvisited(dict);
        unvisited.erase(start);
        current_level.insert(start);
        while(current_level.count(end) == 0 && unvisited.size() > 0){
            for(auto word : current_level){
                for(int l = 0; l < word.length(); ++l){
                    string tmp = word;
                    for(char ch = 'a'; ch <= 'z'; ++ch)
                    if(ch != word[l]){
                        tmp[l] = ch;
                        if(unvisited.count(tmp) > 0){
                            next_level.insert(tmp);
                            adj[tmp].insert(word);
                        }
                    }
                }
            }
            for(auto word : next_level){
                unvisited.erase(word);
            }
            if(next_level.size() == 0) {
                break;
            }
            current_level = next_level;
            next_level.clear();
        }
    }
    void calcAllRoutes(string target, string now, vector<string> &ladder){
        if(now == target){
            ans.push_back(ladder);
            return;
        }
        for(auto next : adj[now]){
            ladder.insert(ladder.begin(), next);
            calcAllRoutes(target, next, ladder);
            ladder.erase(ladder.begin());
        }
        return;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值