#433 Minimum Genetic Mutation

本文探讨如何通过最少的基因突变更,从给定的起始基因串出发,经过基因银行中的有效变异,达到目标基因串。介绍了两种解决方案,一种是利用邻接矩阵进行最短路径搜索,适用于银行规模较小;另一种是逐字符遍历银行,适用于银行规模较大。
摘要由CSDN通过智能技术生成

Description

A gene string can be represented by an 8-character long string, with choices from ‘A’, ‘C’, ‘G’, and ‘T’.

Suppose we need to investigate a mutation from a gene string start to a gene string end where one mutation is defined as one single character changed in the gene string.

For example, “AACCGGTT” --> “AACCGGTA” is one mutation.
There is also a gene bank bank that records all the valid gene mutations. A gene must be in bank to make it a valid gene string.

Given the two gene strings start and end and the gene bank bank, return the minimum number of mutations needed to mutate from start to end. If there is no such a mutation, return -1.

Note that the starting point is assumed to be valid, so it might not be included in the bank.

Examples

Example 1:

Input: start = “AACCGGTT”, end = “AACCGGTA”, bank = [“AACCGGTA”]
Output: 1

Example 2:

Input: start = “AACCGGTT”, end = “AAACGGTA”, bank = [“AACCGGTA”,“AACCGCTA”,“AAACGGTA”]
Output: 2

Example 3:

Input: start = “AAAAACCC”, end = “AACCCCCC”, bank = [“AAAACCCC”,“AAACCCCC”,“AACCCCCC”]
Output: 3

Constraints:

start.length == 8
end.length == 8
0 <= bank.length <= 10
bank[i].length == 8
start, end, and bank[i] consist of only the characters [‘A’, ‘C’, ‘G’, ‘T’].

思路

最开始的思路很简单,因为这其实也是求解最短路径的问题(用bfs)做,每个字符串都可以看作一个状态,一个状态到另一个状态之间的改变就是一条路径,根据这一点,可以构建一个函数”differOne“来判断两个状态是否是直接联通的两个状态(只相差一个单词),从而构建出邻接矩阵
根据邻接矩阵,做bfs,记录move-step,就可以得到最后的答案了,这个方法在这道题里面已经100%了

做完之后再去看发现大家都说这道题和127是一样的,而且他们提供了另一种说法,不是针对bank里面的字符串构建邻接矩阵,而是通过字符串改变gene,再判断改变之后的字符串是否在bank中,也就是对每一个状态,针对字符串中的每一个单词,遍历”A“,”C“,”G“,”T“四个方向,判断one-move可以到达的状态。这种做法在127里面是有效的,但在433中收效甚微(甚至比上面的纯bfs要慢)
这是因为这里的bank.length在0-10之间,遍历邻接矩阵会快许多,在127的5000个bank中,5000 >> word.length * 26,所以第二种方法更为适用

代码

邻接矩阵

class Solution {
    public boolean differOne(String a, String b){
        int count = 0;
        for (int i = 0; i < 8; i++){
            if (a.charAt(i) != b.charAt(i))
                count ++;
        }
        return count == 1;
    }
    public int minMutation(String start, String end, String[] bank) {
        int[][] matrix = new int[bank.length][bank.length];
        // build matrix
        for (int i = 0; i < bank.length; i++){
            for (int j = i + 1; j < bank.length; j++) {
                if (differOne(bank[i], bank[j])){
                    matrix[i][j] = 1;
                    matrix[j][i] = 1;
                }
            }
        }
        
        int level = 1;
        List<Integer> queue = new ArrayList<>();
        int[] hasVisit = new int[bank.length];
        for (int i = 0; i < bank.length; i++){
            if (differOne(start, bank[i])){
                if (bank[i].equals(end))
                    return level;
                queue.add(i);
                hasVisit[i] = 1;
            }
        }
        
        while (queue.size() > 0){
            List<Integer> newQueue = new ArrayList<>();
            level ++;
            for (int num: queue){
                for (int i = 0; i < bank.length; i++){
                    if (matrix[num][i] == 1 && hasVisit[i] == 0){
                        if (bank[i].equals(end))
                            return level;
                        hasVisit[i] = 1;
                        newQueue.add(i);
                    }
                }
            }
            
            queue = new ArrayList<>(newQueue);
        }
        
        return -1;
    }
}

遍历四个方向

class Solution {
    public int minMutation(String start, String end, String[] bank) {
        Set<String> bankSet = new HashSet<>();
        for (String b: bank)
            bankSet.add(b);
        
        List<String> toVisit = new ArrayList<>();
        Set<String> visited = new HashSet<>();
        int level = 1;
        
        toVisit.add(start);
        while(toVisit.size() > 0){
            List<String> newToVisitList = new ArrayList<>();
            for (String pre: toVisit){
                for (int i = 0; i < 8; i++){
                    for (String ch: new String[]{"A", "C", "G", "T"}){
                        StringBuilder sb = new StringBuilder(pre);
                        sb.replace(i, i + 1, ch);
                        String after = sb.toString();
                        if (!visited.contains(after) && bankSet.contains(after)){
                            if (after.equals(end))
                                return level;
                            visited.add(after);
                            newToVisitList.add(after);
                        }
                    }
                }
            }
            toVisit = new ArrayList<>(newToVisitList);
            level ++;
        }
        
        return -1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值