[LeetCode] Minimum Genetic Mutation 最小基因变化
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
这道题跟之前的 Word Ladder 完全是一道题啊,换个故事就直接来啊,越来不走心了啊。不过博主做的时候并没有想起来是之前一样的题,而是先按照脑海里第一个浮现出的思路做的,发现也通过OJ了。博主使用的一种BFS的搜索,先建立bank数组的距离场,这里距离就是两个字符串之间不同字符的个数。然后以start字符串为起点,向周围距离为1的点扩散,采用BFS搜索,每扩散一层,level自加1,当扩散到end字符串时,返回当前level即可。注意我们要把start字符串也加入bank中,而且此时我们也知道start的坐标位置,bank的最后一个位置,然后在建立距离场的时候,调用一个count子函数,用来统计输入的两个字符串之间不同字符的个数,注意dist[i][j]和dist[j][i]是相同,所以我们只用算一次就行了。然后我们进行BFS搜索,用一个visited集合来保存遍历过的字符串,注意检测距离的时候,dist[i][j]和dist[j][i]只要有一个是1,就可以了,参见代码如下:
解法一:
class Solution {
public:
int minMutation(string start, string end, vector<string>& bank) {
if (bank.empty()) return -;
bank.push_back(start);
int res = , n = bank.size();
queue<int> q{{n - }};
unordered_set<int> visited;
vector<vector<int>> dist(n, vector<int>(n, ));
for (int i = ; i < n; ++i) {
for (int j = i + ; j < n; ++j) {
dist[i][j] = count(bank[i], bank[j]);
}
}
while (!q.empty()) {
++res;
for (int i = q.size(); i > ; --i) {
int t = q.front(); q.pop();
visited.insert(t);
for (int j = ; j < n; ++j) {
if ((dist[t][j] != && dist[j][t] != ) || visited.count(j)) continue;
if (bank[j] == end) return res;
q.push(j);
}
}
}
return -;
}
int count(string word1, string word2) {
int cnt = , n = word1.size();
for (int i = ; i < n; ++i) {
if (word1[i] != word2[i]) ++cnt;
}
return cnt;
}
};
下面这种解法跟之前的那道 Word Ladder 是一样的,也是用的BFS搜索。跟上面的解法不同之处在于,对于遍历到的字符串,我们不再有距离场,而是对于每个字符,我们都尝试将其换为一个新的字符,每次只换一个,这样会得到一个新的字符串,如果这个字符串在bank中存在,说明这样变换是合法的,加入visited集合和queue中等待下一次遍历,记得在下次置换字符的时候要将之前的还原。我们在queue中取字符串出来遍历的时候,先检测其是否和end相等,相等的话返回level,参见代码如下:
解法二:
class Solution {
public:
int minMutation(string start, string end, vector<string>& bank) {
if (bank.empty()) return -;
vector<char> gens{'A','C','G','T'};
unordered_set<string> s{bank.begin(), bank.end()};
unordered_set<string> visited;
queue<string> q{{start}};
int level = ;
while (!q.empty()) {
for (int i = q.size(); i > ; --i) {
string t = q.front(); q.pop();
if (t == end) return level;
for (int j = ; j < t.size(); ++j) {
char old = t[j];
for (char c : gens) {
t[j] = c;
if (s.count(t) && !visited.count(t)) {
visited.insert(t);
q.push(t);
}
}
t[j] = old;
}
}
++level;
}
return -;
}
};
再来看一种递归的解法,跟 Permutations 中的解法一有些类似,是遍历bank中的字符串,跟当前的字符串cur相比较,调用isDiffOne()函数判断,若正好跟cur相差一个字符,并且之前没有访问过,那么先在visited数组中标记为true,然后调用递归函数,若返回的不为-1,则用其更新结果res,因为-1代表无法变换成cur。调用完递归后恢复状态,在visited数组中标记为false。循环结束后,看res的值,若还是n+1,表示无法更新,返回-1,否则返回res+1,因为这里的res是变换了一次后到达目标字符串的最小变化次数,所以要加上当前的这次变换。至于isDiffOne()函数就没啥难度了,就是一个一个的比较,不同就累加计数器cnt,参见代码如下:
解法三:
class Solution {
public:
int minMutation(string start, string end, vector<string>& bank) {
if (bank.empty()) return -;
vector<bool> visited(bank.size(), false);
return helper(start, end, bank, visited);
}
int helper(string cur, string end, vector<string>& bank, vector<bool>& visited) {
if (cur == end) return ;
int n = bank.size(), res = n + ;
for (int i = ; i < n; ++i) {
if (visited[i] || !isDiffOne(bank[i], cur)) continue;
visited[i] = true;
int t = helper(bank[i], end, bank, visited);
if (t != -) res = min(res, t);
visited[i] = false;
}
return res == n + ? - : res + ;
}
bool isDiffOne(string& s1, string& s2) {
int cnt = , n = s1.size();
for (int i = ; i < n; ++i) {
if (s1[i] != s2[i]) ++cnt;
if (cnt > ) break;
}
return cnt == ;
}
};
类似题目:
参考资料:
https://leetcode.com/problems/minimum-genetic-mutation/
https://leetcode.com/problems/minimum-genetic-mutation/discuss/91491/dfs-java
https://leetcode.com/problems/minimum-genetic-mutation/discuss/91484/java-solution-using-bfs
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Minimum Genetic Mutation 最小基因变化的更多相关文章
- Leetcode: Minimum Genetic Mutation
A gene string can be represented by an 8-character long string, with choices from "A", &qu ...
- Leetcode 433.最小基因变化
最小基因变化 一条基因序列由一个带有8个字符的字符串表示,其中每个字符都属于 "A", "C", "G", "T"中的任 ...
- [Swift]LeetCode433. 最小基因变化 | Minimum Genetic Mutation
A gene string can be represented by an 8-character long string, with choices from "A", &qu ...
- Java实现 LeetCode 433 最小基因变化
433. 一条基因序列由一个带有8个字符的字符串表示,其中每个字符都属于 "A", "C", "G", "T"中的任意一 ...
- 【LeetCode】433. Minimum Genetic Mutation 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址: https://leetcode. ...
- 【leetcode】433. Minimum Genetic Mutation
题目如下: 解题思路:我的思路很简单,就是利用BFS方法搜索,找到最小值. 代码如下: class Solution(object): def canMutation(self, w, d, c, q ...
- [LeetCode] Minimum Height Trees 最小高度树
For a undirected graph with tree characteristics, we can choose any node as the root. The result gra ...
- [LeetCode] Minimum Window Substring 最小窗口子串
Given a string S and a string T, find the minimum window in S which will contain all the characters ...
- [LeetCode] Minimum Path Sum 最小路径和
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...
随机推荐
- 语句in
Python :in在for中: for name in names: names='1','2','3','4','5' for name in names: print(names) in no ...
- 关于Linux中文件,链接的一些思考
在Unix系统中,操作系统为磁盘上的文本与图像,鼠标键盘操作,网络交互等IO操作设计了一组通用API. 使他们被处理的时候可统一用字节流的方式.所以说,除了进程之外,其他的一切均可看做文件. Linu ...
- 有序的map LinkedHashMap
HashMap是无序的,HashMap在put的时候是根据key的hashcode进行hash然后放入对应的地方.所以在按照一定顺序put进HashMap中,然后遍历出HashMap的顺序跟put的顺 ...
- geotrellis使用(三十六)瓦片入库更新图层
前言 Geotrellis 是针对大数据量栅格数据进行分布式空间计算的框架,这一点毋庸置疑,并且无论采取何种操作,其实都是先将大块的数据切割成一定大小的小数据(专业术语为瓦片),这是分治的思想,也是分 ...
- C语言程序设计(基础)- 第7周作业
为了防止误解,自从本周开始ppt.pta作业.博客作业的命名均与学校教学周一致. 要求一(20经验值) 完成PTA中题目集名为<usth-C语言基础-第七周作业>和<usth-C语言 ...
- C语言博客作业--字符数组-陈张鑫
一.PTA实验作业(4分) 题目1:7-5 查验身份证 1. 本题PTA提交列表(要提交列表,不是结果) 2. 设计思路(伪代码或流程图) 定义变量身份证个数n,合法个数count=0,flag=0, ...
- choose the max from numbers, use scanf and if else (v1:21.9.2017,v2:23.9.2017)
#include<stdio.h> int main(){ int a,b,c,max; printf("请输入一个数值: "); scanf("%d&quo ...
- python的Virtualenv
Virtualenv 虚拟的 Python 环境(简称 venv) 是一个能帮助你在本地目录安装不同版本的 Python 模块的 Python 环境,你可以不再需要在你系统中安装所有东西就能开发并测试 ...
- spring MVC框架入门(外加SSM整合)
spring MVC框架 一.什么是sping MVC Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面.Spring 框架提供了构建 W ...
- jquery实现对div的拖拽功能
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...