力扣433题 最小基因变化

力扣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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值