力扣433题 最小基因变化

本文介绍了一种使用广度优先搜索(BFS)算法来解决力扣433题——最小基因变化的问题。在给定的基因序列start和end,以及基因库bank中,算法寻找使start变化为end所需的最少变化次数。首先,通过邻接矩阵存储基因之间的变化关系,然后利用BFS遍历基因库,标记已访问过的基因,逐步查找目标基因。当end不在bank中时,直接返回-1。最后,通过不断扩展当前层的基因并检查是否达到end,直到找到最小变化次数或遍历完所有可能。

力扣433题 最小基因变化

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

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

例如,“AACCGGTT” --> “AACCGGTA” 就是一次基因变化。
另有一个基因库 bank 记录了所有有效的基因变化,只有基因库中的基因才是有效的基因序列。

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

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

解法我觉得官方题解的BFS很不错,主要是借这道题目来练习写BFS(Breadth_First_Search,广度优先搜索)。
首先回顾数据结构这一节,BFS是在图的遍历引出来的,以广度优先的方式来遍历图的每一个节点。
首先有准备工作:图的存储,即使用邻接矩阵还是邻接表还是什么来存储图。接着开始广度优先遍历。
图的存储的意义:当我们遍历到一个顶点,通过邻接矩阵(等其他存储结构)可以知道从这个顶点出发,下一次搜索的顶点范围。
广度优先遍历,先从第一个顶点开始遍历,标记了该顶点后将该顶点放入队列中,接着从队列弹出这一层(第一个)的元素,依次遍历这些元素的相邻元素,并对这些相邻元素标记,放入队列。后续依次进行,直至全部遍历。其中需要添加一个数组,用来记录哪些顶点已经被遍历了,避免重复遍历。
详细的BFS算法可以参考《大话数据结构》第七章 图,第7.5 图的遍历中的广度优先遍历(P242)
PS:我的是2011年6月第1版,2020年3月第24次印刷

代码如下:(思路等注释在代码里面)

class Solution {
    public int minMutation(String start, String end, String[] bank) {
        //特殊情况,当end不在bank数组里面,直接返回-1
        int n = bank.length;
        boolean flag = true;
        for (int i = 0; i < n; i++) {
            if(end.equals(bank[i])){
                flag = false;
            }
        }
        if(flag) return -1;
        //1.准备工作,存储与每个字符串相差一个字符的元素(类似与邻接矩阵)
        List<Integer>[] obj = new List[n];//存储与第i个元素只相差一个字符的其他元素,类似邻接矩阵
        for (int i = 0; i < n; i++) {
            obj[i] = new ArrayList<>();
        }
        for (int i = 0; i < n; i++) {
            for (int j = i+1; j < n; j++) {
                if(judge(bank[i],bank[j])){
                    obj[i].add(j);
                    obj[j].add(i);
                }
            }
        }
        //2.BFS:一层一层地查询
        Queue<Integer> queue = new ArrayDeque<>();//队列
        boolean[] record = new boolean[n];//避免重复查询
        int step = 1;
        for (int i = 0; i < n; i++) {
            if(judge(start,bank[i])){
                //一步可以得到end情况
                if(end.equals(bank[i])){
                    return step;
                }else {
                    //走一步的情况,即这一层的元素入队
                    queue.offer(i);
                    record[i] = true;
                }
            }
        }
        step++;
        while (!queue.isEmpty()){
            //先将这一层的元素依次出队列,并判断每个元素的下一层是否满足条件
            int sz = queue.size();
            for(int i = 0;i<sz;i++){
                //对每个元素进行判断
                int temp = queue.poll();
                for(int j:obj[temp]){
                    if(record[j]) continue;
                    if(end.equals(bank[j])){
                        return step;
                    }else {
                        record[j] = true;
                        queue.offer(j);
                    }
                }
            }
            step++;
        }
        //包括了走一步无法到达bank里面的元素,返回-1
        //以及已经遍历完了bank,还是无法到达两种情况
        return -1;
    }
    //比较两个字符串是否只有一位不一样
    private boolean judge(String s1, String s2) {
        int cnt = 0;
        for (int i = 0; i < s1.length(); i++) {
            if(s1.charAt(i)!= s2.charAt(i)) cnt++;
        }
        if(cnt == 1) return true;
        return false;
    }
}
力扣第100是判断两个二叉树是否相同的问。 在Java中,判断两个二叉树是否相同的代码如下: ```java public boolean isSameTree(TreeNode p, TreeNode q) { //判断左右子树是否同时为空 if(p==null&&q==null){ return true; } //如果有一个为空,或者左右子树根节点不相等,则返回false if(p==null || q==null || p.val!=q.val){ return false; } //递归判断左右子树 return isSameTree(p.left,q.left) && isSameTree(p.right,q.right); } ``` 在C++中,判断两个二叉树是否相同的代码如下: ```cpp class Solution { public: // 判断两个二叉树是否相同的函数 bool isSameTree(TreeNode* p, TreeNode* q) { // 如果两个节点都是空,则表示这两个子树是相同的,直接返回true if (p == nullptr && q == nullptr) { return true; } // 如果只有一个节点为空,则表示这两个子树不相同,直接返回false else if (p == nullptr || q == nullptr) { return false; } // 如果两个节点的值不相同,则表示这两个子树不相同,直接返回false else if (p->val != q->val) { return false; } // 递归比较左右子树的节点,只有左右子树的对应节点都相同时, // 才表示这两个子树相同,因此需要对两个子树递归调用此函数 else { return isSameTree(p->left, q->left) && isSameTree(p->right, q->right); } } }; ``` 该问的空间复杂度是O(n),由于递归调用,每个函数调用都会将一些数据压入堆栈中,因此需要O(n)的空间来存储这些信息(其中n表示树的高度)。在最坏情况下,两个树的高度相同,因此空间复杂度与节点数成正比 [^4][^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值