当前位置: 首页 > article >正文

LeetCode题练习与总结:最小基因变化--433

一、题目描述

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

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

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

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

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

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

示例 1:

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

示例 2:

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

示例 3:

输入:start = "AAAAACCC", end = "AACCCCCC", bank = ["AAAACCCC","AAACCCCC","AACCCCCC"]
输出:3

提示:

  • start.length == 8
  • end.length == 8
  • 0 <= bank.length <= 10
  • bank[i].length == 8
  • startend 和 bank[i] 仅由字符 ['A', 'C', 'G', 'T'] 组成

二、解题思路

这个问题可以看作是一个无向图的最短路径问题,其中每个基因序列是一个节点,如果两个基因序列之间只有一个字符不同,那么这两个节点之间有一条边。我们的目标是找到从起点基因序列到终点基因序列的最短路径。

以下是解题步骤:

  • 创建一个集合(或使用布尔数组)来记录基因库中哪些基因序列已经被使用过,以避免重复访问。
  • 使用一个队列来进行广度优先搜索(BFS)。初始时,将起点基因序列放入队列中。
  • 在队列不为空的情况下,进行以下操作:
    • 从队列中取出一个基因序列。
    • 如果这个基因序列与终点基因序列相同,返回当前的变化次数。
    • 否则,遍历基因库中的每个基因序列,检查是否只有一个字符不同,并且该基因序列没有被使用过。如果是,将其加入队列,并标记为已使用。
  • 如果队列为空还没有找到终点基因序列,返回 -1。

三、具体代码

import java.util.*;

public class Solution {
    public int minMutation(String start, String end, String[] bank) {
        // 使用集合来记录已经使用过的基因序列
        Set<String> visited = new HashSet<>();
        // 使用队列进行广度优先搜索
        Queue<String> queue = new LinkedList<>();
        // 初始化队列和访问集合
        queue.offer(start);
        visited.add(start);
        // 变化次数
        int steps = 0;

        while (!queue.isEmpty()) {
            int size = queue.size();
            // 遍历当前层的所有节点
            for (int i = 0; i < size; i++) {
                String current = queue.poll();
                // 如果当前节点与终点相同,返回变化次数
                if (current.equals(end)) {
                    return steps;
                }
                // 遍历基因库中的每个基因序列
                for (String gene : bank) {
                    // 如果基因序列没有被使用过,并且只有一个字符不同
                    if (!visited.contains(gene) && isMutation(current, gene)) {
                        queue.offer(gene);
                        visited.add(gene);
                    }
                }
            }
            // 增加变化次数
            steps++;
        }
        // 如果无法完成变化,返回 -1
        return -1;
    }

    // 检查两个基因序列是否只有一个字符不同
    private boolean isMutation(String start, String end) {
        int diff = 0;
        for (int i = 0; i < start.length(); i++) {
            if (start.charAt(i) != end.charAt(i)) {
                diff++;
                if (diff > 1) {
                    return false;
                }
            }
        }
        return diff == 1;
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 初始化阶段,将起始基因序列 start 加入队列,这一步的时间复杂度是 O(1)。

  • 在广度优先搜索(BFS)过程中,我们遍历队列中的每个元素,并对每个元素检查基因库中的所有基因序列。假设基因库的大小为 n,那么在每层BFS中,我们需要检查 n 个基因序列,并且对于每个基因序列,我们执行 isMutation 方法来检查是否只有一个字符不同,isMutation 方法的时间复杂度是 O(8),因为每个基因序列的长度是固定的 8。

  • BFS 可能会遍历所有 n 个基因序列,因为最坏情况下每个基因序列都可能被加入到队列中。因此,队列的大小最多可能是 n。

综合以上分析,总的时间复杂度是 O(n^2 * 8),可以简化为 O(n^2),因为 8 是一个常数。

2. 空间复杂度
  • visited 集合用于存储已经访问过的基因序列,最坏情况下需要存储 n 个基因序列,因此空间复杂度是 O(n)。

  • 队列 queue 在最坏情况下可能包含所有 n 个基因序列,因此空间复杂度也是 O(n)。

综合以上分析,总的空间复杂度是 O(n) + O(n),可以简化为 O(n),因为两个 O(n) 是同阶的。

五、总结知识点

  • 面向对象编程(OOP)

    • 类定义(public class Solution)。
    • 方法定义(public int minMutation(...) 和 private boolean isMutation(...))。
  • 数据结构

    • 集合(Set<String>):用于存储已经访问过的基因序列,确保不会重复访问。
    • 队列(Queue<String>):用于实现广度优先搜索(BFS)。
  • 算法

    • 广度优先搜索(BFS):用于在无向图中找到从起点到终点的最短路径。
    • 字符串比较:用于判断两个基因序列是否只有一个字符不同。
  • 字符串操作

    • 使用 charAt(int index) 方法获取字符串中指定位置的字符。
    • 使用 equals(Object anObject) 方法比较两个字符串是否相等。
  • 控制结构

    • 循环结构:for 循环用于遍历队列中的元素和字符串中的字符。
    • 条件语句:if 语句用于检查条件是否满足,并据此执行不同的操作。
  • 集合操作

    • 使用 add(E e) 方法向集合中添加元素。
    • 使用 contains(Object o) 方法检查集合中是否包含特定的元素。
  • 队列操作

    • 使用 offer(E e) 方法向队列中添加元素。
    • 使用 poll() 方法从队列中取出并移除头部元素。
    • 使用 size() 方法获取队列中的元素数量。
  • 错误处理

    • 如果无法从起始基因序列变换到目标基因序列,则返回 -1

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。


http://www.kler.cn/a/417700.html

相关文章:

  • CSS系列(36)-- Containment详解
  • Flink调优----反压处理
  • 【西安电子科技大学考研】25官方复试专业课参考书目汇总
  • 极狐GitLab 17.7正式发布,可从 GitLab 丝滑迁移至极狐GitLab【一】
  • Centos下的OpenSSH服务器和客户端
  • 论文DiffBP: generative diffusion of 3D molecules for target protein binding
  • 【踩坑】git中文乱码问题
  • 从0开始边做边学,用vue和python做一个博客,非规范化项目,怎么简单怎么弄,跑的起来有啥毛病解决啥毛病(一)
  • IIS管理器、Sql Server、windows操作系统,nginx
  • 【前端】JavaScript中的字面量概念与应用详解
  • Istio_05_Istio架构
  • Nacos安装指南
  • Webman中实现定时任务
  • 【拥抱AI】RAG如何提高向量化的质量
  • 排序学习整理(2)
  • HDFS知识总结
  • 网络安全:攻防技术-Google Hacking的实现及应用
  • Android复习简答题
  • 【Nativeshell】flutter的pc跨平台框架学习记录<二> 窗口间通信
  • 条件数:概念、矩阵中的应用及实际工业场景应用
  • 鬼谷子的捭阖之道
  • BBC将 IT 系统迁移至基于AWS的RISE with SAP
  • 【PX4_Autopolite飞控源码】中飞控板初始化过程中的引脚IO控制(拉低/拉高)
  • YOLO系列论文综述(从YOLOv1到YOLOv11)【第15篇(完结):讨论和未来展望】
  • 数据结构 (14)数组的定义与运算
  • 【网络安全】记一次杀猪盘渗透实战