哈希表初始化+双向BFS+剪枝优化(字典树+记录路径最短距离+记录总最短距离) 127. 单词接龙 126. 单词接龙 II

24 篇文章 1 订阅
11 篇文章 0 订阅

127. 单词接龙

给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:

每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:

如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:

输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出: 5

解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
     返回它的长度 5

示例 2:

输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

输出: 0

解释: endWord "cog" 不在字典中,所以无法进行转换。

解题
将wordlist的每一种变法存在map中:map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);

begin入队后将map中begin的可变化字符串挨个入队:

         for(int i=0;i<beginWord.size();i++){  //map里的三个都进去了
            for(auto t:map[beginWord.substr(0,i)+"*"+beginWord.substr(i+1)])
                Q.push(t);
                map.erase(beginWord.substr(0,i)+"*"+beginWord.substr(i+1));

并删除map中的该key;
找到endword则输出res,否则输出0;

单向BFS

class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        //预处理,把单词放入*中
        for(string s:wordList){
            for(int i=0;i<s.size();i++)
            map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);
        }
        res=0;
        queue<string> Q;
        Q.push(beginword);
        //cout<<Q.front();
         while(!Q.empty()){
             ++res;
            int size=Q.size();
            while(size--){
            string tmp=Q.front();
            Q.pop();
            if(tmp==endWord) return res;
            for(int i=0;i<tmp.size();i++){  //map里的三个都进去了
            for(auto t:map[tmp.substr(0,i)+"*"+tmp.substr(i+1)])
                Q.push(t);
                map.erase(tmp.substr(0,i)+"*"+tmp.substr(i+1));
            }
            }
         }
        return 0;
    }
private:
    int res;
    unordered_map<string,vector<string>> map;
};

双向BFS
存储beginword一路变化过来的字符串到res1;
存储endword一路变化过来的字符串到res2;
若beginword正在变化的字符串在res2中出现过,返回当前res;
若endword正在变化的字符串在res1中出现过,返回当前res;

注意点
首先判断wordlist中有无endword,没有则直接返回0;

class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        //预处理,把单词放入*中
        bool flag=0;
        for(string s:wordList){
            if(s==endWord) flag=1;
            for(int i=0;i<s.size();i++)
            map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);
        }
        if(!flag) return 0;
        result=0;
        queue<string> Q;
        queue<string> Q2;
        Q.push(beginWord);
        Q2.push(endWord);
 //反向查找

         while(!Q.empty()||!Q2.empty()){
            int size=Q.size();
            while(size--){
            string tmp=Q.front();
            if(res2[tmp]) return result;
            res1[tmp]=1;
            Q.pop();
            for(int i=0;i<tmp.size();i++){  //map里的三个都进去了
            for(auto t:map[tmp.substr(0,i)+"*"+tmp.substr(i+1)])
                Q.push(t);
                map.erase(tmp.substr(0,i)+"*"+tmp.substr(i+1));
            }
            }
            ++result;
            size=Q2.size();
            while(size--){
            string tmp=Q2.front();
            if(res1[tmp]) return result;
            res2[tmp]=1;
            Q2.pop();
            for(int i=0;i<tmp.size();i++){  //map里的三个都进去了
            for(auto t:map[tmp.substr(0,i)+"*"+tmp.substr(i+1)])
                Q2.push(t);
                map.erase(tmp.substr(0,i)+"*"+tmp.substr(i+1));
            }
        }
        ++result;
        }
        return 0;
    }
private:
    int result;
    unordered_map<string,vector<string>> map;
    unordered_map<string,bool> res1;
    unordered_map<string,bool> res2;
};

126. 单词接龙 II

给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:

每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:

如果不存在这样的转换序列,返回一个空列表。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:

输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出:
[
  ["hit","hot","dot","dog","cog"],
  ["hit","hot","lot","log","cog"]
]

示例 2:

输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

输出: []

解释: endWord “cog” 不在字典中,所以不存在符合要求的转换序列。

解题
上题字典优化的基础上再优化四步:
(1)BFS找最短距离
(2)BFS建立字典树
(3)BFS过程中找到每个单词的最短变化步数
(4)dfs时超过最短距离剪枝;curword超过该单词的最短步数剪枝;直接遍历字典树dfs更快;


BFS找最短距离,DFS找路径;

class Solution {
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        for(auto s:wordList)
            for(int i=0;i<s.size();i++)
                map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);

        queue<string> Q;
        mincnt=-1;
        Q.push(beginWord);
        visited[beginWord]=1;
        bool flag=0;
        while(!Q.empty()){
            mincnt++;
            int size=Q.size();
            while(size--){
                string T=Q.front();
                Q.pop();
                if(T==endWord) {
                    flag=1;
                    break;
                }
                for(int i=0;i<T.size();i++)
                    for(auto s:map[T.substr(0,i)+"*"+T.substr(i+1)])
                    if(!visited[s]){
                        visited[s]=1;
                        Q.push(s);
                    }
            }
            if(flag) break;
        }
        visited.clear();
        dfs(beginWord,endWord,0);
        return res;

    }
private:
    unordered_map<string,vector<string>> map;
    vector<string> tmp;
    vector<vector<string>> res;
    unordered_map<string,bool> visited;
    int mincnt;
    void dfs(string curword, string endWord,int cnt){
        if(visited[curword]||cnt>mincnt) return;
        if(curword==endWord) {
           tmp.push_back(curword);
           res.push_back(tmp); 
           tmp.pop_back();
           return;
        } 
            visited[curword]=1;
            tmp.push_back(curword);
            for(int i=0;i<curword.size();i++)
               for(auto t:map[curword.substr(0,i)+"*"+curword.substr(i+1)])
                   dfs(t,endWord,cnt+1);
            tmp.pop_back();
            visited[curword]=0;
        return;
    }
};

DFS找路径,并且找最短距离;

class Solution {
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        for(auto s:wordList)
            for(int i=0;i<s.size();i++)
                map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);

        mincnt=INT_MAX;
        dfs(beginWord,endWord,0);
        return res;

    }
private:
    unordered_map<string,vector<string>> map;
    vector<string> tmp;
    vector<vector<string>> res;
    unordered_map<string,bool> visited;
    int mincnt;
    void dfs(string curword, string endWord,int cnt){
        if(visited[curword]||cnt>mincnt) return;  //剪枝1
        if(!distance[curword]||distance[curword]>=cnt){  //剪枝2
            distance[curword]=cnt;
        }
        else return;
        if(curword==endWord) {
            if(cnt<mincnt){
                mincnt=cnt;
                res.clear();
            }
           tmp.push_back(curword);
           res.push_back(tmp); 
           tmp.pop_back();
           return;
        } 
            visited[curword]=1;
            tmp.push_back(curword);
            for(int i=0;i<curword.size();i++)
               for(auto t:map[curword.substr(0,i)+"*"+curword.substr(i+1)])
                   dfs(t,endWord,cnt+1);
            tmp.pop_back();
            visited[curword]=0;
        return;
    }
};

BFS找最短距离+建立字典树+DFS找路径+DFS路径剪枝

class Solution {
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        for(auto s:wordList)
            for(int i=0;i<s.size();i++)
                map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);
         queue<string> Q;
        mincnt=-1;
        Q.push(beginWord);
        visited[beginWord]=1;
        mincnt=INT_MAX;
        int cnt=-1;
        while(!Q.empty()){
            cnt++;
            int size=Q.size();
            while(size--){
                string T=Q.front();
                Q.pop();
                if(T==endWord) {
                    mincnt=min(mincnt,cnt);
                }
                for(int i=0;i<T.size();i++)
                    for(auto s:map[T.substr(0,i)+"*"+T.substr(i+1)]){
                    HASHMAP[T].push_back(s);  //建立字典树优化
                    if(!visited[s]){
                        
                        visited[s]=1;
                        Q.push(s);
                    }
                    }
            }
        }
        visited.clear();
        dfs(beginWord,endWord,0);
        return res;

    }
private:
    unordered_map<string,int> distance;
    unordered_map<string,vector<string>> map;
    vector<string> tmp;
    vector<vector<string>> res;
    unordered_map<string,bool> visited;
    unordered_map<string,vector<string>> HASHMAP;
    int mincnt;
    void dfs(string curword, string endWord,int cnt){
        if(visited[curword]||cnt>mincnt) return;    //剪枝1

        if(!distance[curword]||distance[curword]>=cnt){  //剪枝2
            distance[curword]=cnt;
        }
        else return;

        if(curword==endWord) {
           tmp.push_back(curword);
           res.push_back(tmp); 
           tmp.pop_back();
           return;
        } 
            visited[curword]=1;
            tmp.push_back(curword);

            for(auto t:HASHMAP[curword])
                dfs(t,endWord,cnt+1);
            tmp.pop_back();
            visited[curword]=0;
        return;
    }
};

通过代码

将路径剪枝distance在bfs过程中完成,即可优化速度,通过所有样例
BFS——找最短距离+建立字典树+找到每个单词的最短变化步数

class Solution {
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        for(auto s:wordList)
            for(int i=0;i<s.size();i++)
                map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);
         queue<string> Q;
        mincnt=-1;
        Q.push(beginWord);
        visited[beginWord]=1;
        mincnt=INT_MAX;
        int cnt=-1;
        while(!Q.empty()){
            cnt++;
            int size=Q.size();
            while(size--){
                string T=Q.front();
                Q.pop();
                if(T==endWord) {
                    mincnt=min(mincnt,cnt);
                }
                for(int i=0;i<T.size();i++)
                    for(auto s:map[T.substr(0,i)+"*"+T.substr(i+1)]){
                    HASHMAP[T].push_back(s);  //建立字典树优化
                    if(!visited[s]){
                        distance[s]=cnt;
                        visited[s]=1;
                        Q.push(s);
                    }
                }
            }
        }
        visited.clear();
        dfs(beginWord,endWord,0);
        return res;

    }
private:
    unordered_map<string,int> distance;
    unordered_map<string,vector<string>> map;
    vector<string> tmp;
    vector<vector<string>> res;
    unordered_map<string,bool> visited;
    unordered_map<string,vector<string>> HASHMAP;
    int mincnt;
    void dfs(string curword, string endWord,int cnt){
        if(visited[curword]||cnt>mincnt) return;    //剪枝1

        if(distance[curword]<cnt-1) return; //剪枝2 

        if(curword==endWord) {
           tmp.push_back(curword);
           res.push_back(tmp); 
           tmp.pop_back();
           return;
        } 
            visited[curword]=1;
            tmp.push_back(curword);

            for(auto t:HASHMAP[curword])
                dfs(t,endWord,cnt+1);
            tmp.pop_back();
            visited[curword]=0;
        return;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值