leetcode#127 单词接龙

本文介绍了一种使用广度优先搜索(BFS)和哈希映射优化来解决LeetCode上的单词接龙问题的方法。通过创建虚拟节点和建立边的连接,可以高效地找出两个单词之间的最短转换序列。在代码实现中,首先对每个单词构建其可能的转化状态,并建立邻接列表表示单词间的连接。然后,从起点开始进行BFS搜索,直到找到终点,返回路径长度的一半加一作为最短路径长度。若找不到路径,则返回0。
摘要由CSDN通过智能技术生成

leetcode#127 单词接龙

题目:

字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列:

  • 序列中第一个单词是 beginWord 。
  • 序列中最后一个单词是 endWord 。
  • 每次转换只能改变一个字母。
  • 转换过程中的中间单词必须是字典 wordList 中的单词。

给你两个单词 beginWord 和 endWord 和一个字典 wordList ,找到从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0。

示例:
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
输出:5
解释:一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。

思路:

和上一个题一样,bfs。
上一个题目中我们对当前层的一个节点,判断哪些是他的子节点的时候,我们要遍历一遍整个wordList,看看哪个单词没有被加入队列过并且这个单词和当前单词只差一个字母,效率十分的低。

在这道题中,我们可以进行建图优化,直接建图,只有相差一个字母的才能连接到一起,用哈希表存储他们的所有状态,有相同状态的会连接到一起,省去比较的过程。

具体地,我们可以创建虚拟节点。对于单词 hit,我们创建三个虚拟节点 * it、h * t、hi *,并让 hit 向这三个虚拟节点分别连一条边即可。如果一个单词能够转化为 hit,那么该单词必然会连接到这三个虚拟节点之一。对于每一个单词,我们枚举它连接到的虚拟节点,把该单词对应的 id 与这些虚拟节点对应的 id 相连即可。

最后我们将起点加入队列开始广度优先搜索,当搜索到终点时,我们就找到了最短路径的长度。注意因为添加了虚拟节点,所以我们得到的距离为实际最短路径长度的两倍。同时我们并未计算起点对答案的贡献,所以我们应当返回距离的一半再加一的结果。

代码:

class Solution
{
public:
    int cnt = 0;
    unordered_map<string, int> mp;
    vector<vector<int>> edge;
    void addword(string s)
    {
        if (!mp.count(s))
            mp[s] = cnt++;
        edge.emplace_back();
    }
    void addedge(string s)
    {
        int len = s.length();
        addword(s);
        int id_s = mp[s];
        for (int i = 0; i < len; ++i)
        {
            char tmp = s[i];
            s[i] = '*';
            addword(s);
            int id_tmp = mp[s];
            edge[id_s].push_back(id_tmp);
            edge[id_tmp].push_back(id_s);
            s[i] = tmp;
        }
    }
    int ladderLength(string beginWord, string endWord, vector<string> &wordList)
    {
        int len = wordList.size(), step = 0;
        addedge(beginWord);
        for (int i = 0; i < len; ++i)
            addedge(wordList[i]);
        if (!mp.count(endWord))
            return 0;
        bool vis[cnt];
        memset(vis,false,sizeof(vis));
        vis[mp[beginWord]] = true;
        queue<int> qu;
        qu.push(mp[beginWord]);
        while (!qu.empty())
        {
            ++step;
            int size = qu.size();
            for (int i = 0; i < size; ++i)
            {
                int now = qu.front();
                qu.pop();
                if (now == mp[endWord])
                    return step / 2 + 1;
                for (int i = 0; i < edge[now].size(); ++i)
                {
                    if (!vis[edge[now][i]])
                        qu.push(edge[now][i]);
                    vis[edge[now][i]] = true;
                }
            }
        }
        return 0;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值