BFS解决最短路问题_最小基因变化、单词接龙_C++

BFS解决最短路问题_最小基因变化、单词接龙_C++


1. 题目解析


leetcode链接:https://leetcode.cn/problems/minimum-genetic-mutation/submissions/569463000/

基因序列可以表示为一条由 8 个字符组成的字符串,其中每个字符都是 'A''C''G''T' 之一。

假设我们需要调查从基因序列 start 变为 end 所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。

  • 例如,"AACCGGTT" --> "AACCGGTA" 就是一次基因变化。

另有一个基因库 bank 记录了所有有效的基因变化,只有基因库中的基因才是有效的基因序列。(变化后的基因必须位于基因库 bank 中)

给你两个基因序列 startend ,以及一个基因库 bank ,请你找出并返回能够使 start 变化为 end 所需的最少变化次数。如果无法完成此基因变化,返回 -1 。

注意:起始基因序列 start 默认是有效的,但是它并不一定会出现在基因库中。

示例 1:

输入:start = "AACCGGTT", end = "AACCGGTA", bank = ["AACCGGTA"]
输出:1

示例 2:

输入:start = "AACCGGTT", end = "AAACGGTA", bank = ["AACCGGTA","AACCGCTA","AAACGGTA"]
输出:2

大白话分析:

  • 一个基因要变化到另一个基因,一次只能变化一个字母,而且变化后形成的基因,必须存在于基因库中。

2. 算法分析


1. 转化为边权为1的最短路问题:

在这里插入图片描述

如图,假设起始基因为AA,可以变化的字符只有A、C、T,先对AA进行变化,就可以得出四个不同的基因。假设目标基因是CT,那么CT其实可以通过ATCA变化得到。这些变化关系和基因构成了一副无向图,并且边权唯一。而且图一定是有限的。

如此一来,就将该问题转化为了边权为1的最短路问题。

2. 实现细节:

  • 每次进行基因变化时,需要判断变化产生的基因是否存在于基因库中。你当然可以暴力遍历基因库,但是这样效率很慢,我们可以将基因库中的基因放在一个哈希表中,提升效率。
  • 还需要一个vis哈希表,来标记这个基因有没有被搜索过,避免重复搜索。
  • 如果目标基因不在基因库中,则一定是无法通过变化得到的,直接返回-1;如果目标基因就等于起始基因,直接不需要变化了,直接返回0。

3. 代码实现


class Solution {
public:
    int minMutation(string startGene, string endGene, vector<string>& bank) 
    {
        unordered_set<string> vis;  // 用来标记已经搜索过的状态
        unordered_set<string> hash(bank.begin(), bank.end());   // 存储基因库里面的字符串
        string change = "ACGT";

        if (startGene == endGene) return 0;
        if (!hash.count(endGene)) return -1;

        queue<string> q;
        q.push(startGene);
        vis.insert(startGene);

        int ret = 0;
        while(q.size())
        {
            ret++;
            int sz = q.size();
            while(sz--)
            {
                string t = q.front();
                q.pop();
                for (int i = 0; i < 8; i++)
                {
                    string tmp = t;		// 细节,不能直接改变t
                    for (int j = 0; j < 4; j++)
                    {
                        tmp[i] = change[j];
                        if (hash.count(tmp) && !vis.count(tmp))
                        {
                            if (tmp == endGene) return ret;
                            q.push(tmp);
                            vis.insert(tmp);
                        }
                    }
                }
            }
        }
        return -1;
    }
};

4. 举一反三:单词接龙


leetcode链接:https://leetcode.cn/problems/om3reC/description/

class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) 
    {
        unordered_set<string> vis;
        unordered_set<string> hash(wordList.begin(), wordList.end());

        if (beginWord == endWord) return 1;
        if (!hash.count(endWord)) return 0;

        queue<string> q;
        q.push(beginWord);
        vis.insert(beginWord);

        int count = 1;
        while (q.size())
        {
            int sz = q.size();
            count++;
            while (sz--)
            {
                string t = q.front();
                q.pop();
                for (int i = 0; i < t.size(); i++)
                {
                    string tmp = t;
                    for (char ch = 'a'; ch <= 'z'; ch++)
                    {
                        tmp[i] = ch;
                        if (hash.count(tmp) && !vis.count(tmp))
                        {
                            if (tmp == endWord) return count;
                            q.push(tmp);
                            vis.insert(tmp);
                        }
                    }
                }
            }
        }
        return 0;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-指短琴长-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值