Problem Statement
(Source) A gene string can be represented by an 8-character long string, with choices from "A"
, "C"
, "G"
, "T"
.
Suppose we need to investigate about a mutation (mutation from “start” to “end”), where ONE mutation is defined as ONE single character changed in the gene string.
For example, "AACCGGTT"
-> "AACCGGTA"
is 1 mutation.
Also, there is a given gene “bank”, which records all the valid gene mutations. A gene must be in the bank to make it a valid gene string.
Now, given 3 things - start, end, bank, your task is to determine what is the minimum number of mutations needed to mutate from “start” to “end”. If there is no such a mutation, return -1.
Note:
- Starting point is assumed to be valid, so it might not be included in the bank.
- If multiple mutations are needed, all mutations during in the sequence must be valid.
- You may assume start and end string is not the same.
Example 1:
start: "AACCGGTT" end: "AACCGGTA" bank: ["AACCGGTA"] return: 1
Example 2:
start: "AACCGGTT" end: "AAACGGTA" bank: ["AACCGGTA", "AACCGCTA", "AAACGGTA"] return: 2
Example 3:
start: "AAAAACCC" end: "AACCCCCC" bank: ["AAAACCCC", "AAACCCCC", "AACCCCCC"] return: 3
Solution
class Solution(object):
def minMutation(self, start, end, bank):
"""
:type start: str
:type end: str
:type bank: List[str]
:rtype: int
"""
if end not in bank:
return -1
d1, d2 = set([start]), set([end])
i, n = 1, len(bank)
explored = set([start, end])
while i <= n:
if len(d1) > len(d2):
d1, d2 = d2, d1
d = set()
while d1:
x = d1.pop()
for gene in bank:
if gene not in d1:
if self.is_valid(x, gene):
if gene in d2:
return i
if gene not in explored:
d.add(gene)
explored.add(gene)
d1, i = d, i + 1
return -1
def is_valid(self, x, y):
return sum(1 for i in xrange(8) if x[i] != y[i]) == 1