【Lintcode】1244. Minimum Genetic Mutation

题目地址:

https://www.lintcode.com/problem/minimum-genetic-mutation/description

给定两个基因序列(字符串) s t a r t start start e n d end end,全部由 A C G T ACGT ACGT四个字母组成。再给定一个基因库(字符串数组),允许从一个基因序列通过基因突变的方式变成另一个序列,突变是指基因序列中某个基因变成了 A C G T ACGT ACGT中的另一个,并且只能突变成基因库里的基因序列。问从 s t a r t start start e n d end end至少要突变多少步。如果不存在突变的方式能到 e n d end end则返回 − 1 -1 1

思路是双向BFS。注意需要分层遍历,还要另开一个函数专门算某个基因序列能突变成哪些基因(也就是求隐式图中该字符串的邻接点)。代码如下:

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;

public class Solution {
    /**
     * @param start:
     * @param end:
     * @param bank:
     * @return: the minimum number of mutations needed to mutate from "start" to "end"
     */
    public int minMutation(String start, String end, String[] bank) {
        // Write your code here
        if (start.equals(end)) {
            return 0;
        }
        
        Set<String> setBank = new HashSet<>();
        for (String s : bank) {
            setBank.add(s);
        }
        // 如果end不在基因库里,那直接返回false
        if (!setBank.contains(end)) {
            return -1;
        }
    
        char[] genes = {'A', 'C', 'G', 'T'};
        
        Queue<String> beginQueue = new LinkedList<>(), endQueue = new LinkedList<>();
        Set<String> beginVisited = new HashSet<>(), endVisited = new HashSet<>();
        beginQueue.offer(start);
        beginVisited.add(start);
        endQueue.offer(end);
        endVisited.add(end);
        
        int res = 0;
        while (!beginQueue.isEmpty() && !endQueue.isEmpty()) {
            int beginSize = beginQueue.size(), endSize = endQueue.size();
            for (int i = 0; i < beginSize; i++) {
                String cur = beginQueue.poll();
                if (endVisited.contains(cur)) {
                    return res;
                }
                for (String neighbor : getNeighbors(cur, setBank, beginVisited, genes)) {
                    beginQueue.offer(neighbor);
                    beginVisited.add(neighbor);
                }
            }
            res++;
    
            for (int i = 0; i < endSize; i++) {
                String cur = endQueue.poll();
                if (beginVisited.contains(cur)) {
                    return res;
                }
                for (String neighbor : getNeighbors(cur, setBank, endVisited, genes)) {
                    endQueue.offer(neighbor);
                    endVisited.add(neighbor);
                }
            }
            res++;
        }
        // 如果两个队列某个为空,说明某个方向已经无法再拓展,那就不存在路径,返回-1
        return -1;
    }
    
    private Set<String> getNeighbors(String start, Set<String> bank, Set<String> visited, char[] genes) {
        Set<String> neighbors = new HashSet<>();
        for (int i = 0; i < start.length(); i++) {
            for (char gene : genes) {
                if (start.charAt(i) != gene) {
                    String neighbor = start.substring(0, i) + gene + start.substring(i + 1);
                    if (bank.contains(neighbor) && !visited.contains(neighbor)) {
                        neighbors.add(neighbor);
                    }
                }
            }
        }
        
        return neighbors;
    }
}

时空复杂度 O ( V + E ) O(V+E) O(V+E)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值