website/content.en/ChapterFour/0400~0499/0433.Minimum-Genetic-Mutation.md
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:
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
Now given 3 parameters — start, end, bank, which respectively represent the starting gene sequence, the target gene sequence, and the gene bank, find the minimum number of changes needed to transform the starting gene sequence into the target gene sequence. If the target transformation cannot be achieved, return -1.
Note:
package leetcode
// Solution 1 BFS
func minMutation(start string, end string, bank []string) int {
wordMap, que, depth := getWordMap(bank, start), []string{start}, 0
for len(que) > 0 {
depth++
qlen := len(que)
for i := 0; i < qlen; i++ {
word := que[0]
que = que[1:]
candidates := getCandidates433(word)
for _, candidate := range candidates {
if _, ok := wordMap[candidate]; ok {
if candidate == end {
return depth
}
delete(wordMap, candidate)
que = append(que, candidate)
}
}
}
}
return -1
}
func getCandidates433(word string) []string {
var res []string
for i := 0; i < 26; i++ {
for j := 0; j < len(word); j++ {
if word[j] != byte(int('A')+i) {
res = append(res, word[:j]+string(int('A')+i)+word[j+1:])
}
}
}
return res
}
// Solution 2 DFS
func minMutation1(start string, end string, bank []string) int {
endGene := convert(end)
startGene := convert(start)
m := make(map[uint32]struct{})
for _, gene := range bank {
m[convert(gene)] = struct{}{}
}
if _, ok := m[endGene]; !ok {
return -1
}
if check(startGene ^ endGene) {
return 1
}
delete(m, startGene)
step := make(map[uint32]int)
step[endGene] = 0
return dfsMutation(startGene, m, step)
}
func dfsMutation(start uint32, m map[uint32]struct{}, step map[uint32]int) int {
if v, ok := step[start]; ok {
return v
}
c := -1
step[start] = c
for k := range m {
if check(k ^ start) {
next := dfsMutation(k, m, step)
if next != -1 {
if c == -1 || c > next {
c = next + 1
}
}
}
}
step[start] = c
return c
}
func check(val uint32) bool {
if val == 0 {
return false
}
if val&(val-1) == 0 {
return true
}
for val > 0 {
if val == 3 {
return true
}
if val&3 != 0 {
return false
}
val >>= 2
}
return false
}
func convert(gene string) uint32 {
var v uint32
for _, c := range gene {
v <<= 2
switch c {
case 'C':
v |= 1
case 'G':
v |= 2
case 'T':
v |= 3
}
}
return v
}