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
一道draft里边的题。跟同学一块看了下。
发现跟word ladder很像。算的是最小距离,所以要用bfs。如果是算全部的结果的话一般会用dfs。
思路有了以后就开始实现了。
觉得比较慢的地方是在如何找到只相差一个字符的字符串那里。用了String拼接的方法。将字典转化成set。如果在字典中找到了这个值,那么加入到结果集,准备放入队列,并且把它删除掉。为了防止循环。
还有一个细节:在计算高度的时候,使用两个计数器, preLevel, curLevel, 分别记录的是上一层还有几个没有遍历完,以及当前层有几个需要遍历;在这个while循环里边,是不会对curLevel进行减法运算的,每一次都是对preLevel--, 当 prelevel == 0的时候,说明上面一层的元素都被遍历过了,这个时候再更新层信息,也就是代码里的move。更新的时间也要主意,要等到把下一层的neighbour添加完(也就是curLevel++ 这段代码要先执行),然后再判断是否需要更新preLevel, curLevel的值。
最后,如果在while循环里找到结果,直接返回,move+1, 这里举个例子应该能够解释的通; 在while循环外,return -1;
代码:
public int minMutation(String start, String end, String[] bank) {
//trie?
//bfs应该没跑了
if(bank == null || bank.length == 0) return -1;
if(start.length() != end.length()) return -1;
boolean find = false;
HashSet<String> bankSet = new HashSet<String>();
for(String item: bank) bankSet.add(item);
Queue<String> queue = new LinkedList<>();
queue.offer(start);
int moves = 0;
int answer = 0;
int preLevel = 1;
int curLevel = 0;
while(!queue.isEmpty()){
String string = queue.poll();
List<String> neighbours = getOneMutate(string, bankSet);
for(String neighbour: neighbours){
curLevel++;
queue.offer(neighbour);
if(neighbour.equals(end)){
find = true;
return moves+1;
}
}
preLevel--;
if(preLevel == 0){
preLevel = curLevel;
curLevel = 0;
moves++;
}
}
return -1;
}
private static char[] GENES = {'A', 'C', 'T', 'G'};
private List<String> getOneMutate(String s, HashSet<String> bankSet){
List<String> result = new ArrayList<>();
//自己动
for(int i=0;i<s.length();i++){
//change one bit
for(int j=0;j<GENES.length;j++){
String newString = s.substring(0, i)+GENES[j]+s.substring(i+1);
if(bankSet.contains(newString)){
result.add(newString);
bankSet.remove(newString);
}
}
}
return result;
}