题目描述
思路
BFS
根据题意,要将一个基因序列A变化为另一个基因序列B,需要满足以下条件:
- A与B之间只有一个字符不同;
- 变化字符只能从’A’、‘C’、‘G’、'T’中进行选择;
- 变换后的序列B必须在字符串数组bank中。
根据这些条件,可以尝试所有合法的基因变化,并找到最小的变换次数即可。
具体实现如下:
- 如果start和end相等,直接返回0;如果end不在bank中,按照规则变化都无法生成,直接返回-1。
- 将可能变换的基因s从队列中取出,按照上述变换规则尝试所有可能的变化后的基因,比如一段AACCGGTT基因,依次对每一个字符尝试变换,共能得到3*8=24种不同的基因序列。
- 检测当前生成的基因序列的合法性,即判断该序列是否在bank中出现,如果出现则基因合法,如果未出现则不合法丢弃;其次还需要记录已经遍历过的基因序列,如果该基因序列已被遍历过,则可以直接跳过;如果合法且未被遍历过的基因序列,则加入队列。
- 如果当前变换后的基因序列与end相等,则直接返回最小变化次数即可;如果队列中所有元素都已经遍历过还无法成为end,则返回-1。
Python实现
class Solution:
def minMutation(self, start: str, end: str, bank: List[str]) -> int:
if start == end:
return 0
bank = set(bank)
if end not in bank:
return -1
q = deque([(start, 0)])
while q:
cur, step = q.popleft()
for i, x in enumerate(cur):
for y in "ACGT":
if y != x:
nxt = cur[:i] + y + cur[i+1:]
if nxt in bank:
if nxt == end:
return step+1
bank.remove(nxt)
q.append((nxt, step+1))
return -1
Java实现
class Solution {
public int minMutation(String start, String end, String[] bank) {
Set<String> cnt = new HashSet<String>();
Set<String> visited = new HashSet<String>();
char[] keys = {'A', 'C', 'G', 'T'};
for (String w : bank) {
cnt.add(w);
}
if (start.equals(end)) {
return 0;
}
if (!cnt.contains(end)) {
return -1;
}
Queue<String> queue = new ArrayDeque<String>();
queue.offer(start);
visited.add(start);
int step = 1;
while (!queue.isEmpty()) {
int sz = queue.size();
for (int i = 0; i < sz; i++) {
String curr = queue.poll();
for (int j = 0; j < 8; j++) {
for (int k = 0; k < 4; k++) {
if (keys[k] != curr.charAt(j)) {
StringBuffer sb = new StringBuffer(curr);
sb.setCharAt(j, keys[k]);
String next = sb.toString();
if (!visited.contains(next) && cnt.contains(next)) {
if (next.equals(end)) {
return step;
}
queue.offer(next);
visited.add(next);
}
}
}
}
}
step++;
}
return -1;
}
}