Leetcode - 433:最小基因变化
题目:
基因序列可以表示为一条由 8 个字符组成的字符串,其中每个字符都是 'A'
、'C'
、'G'
和 'T'
之一。
假设我们需要调查从基因序列 start
变为 end
所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。
- 例如,
"AACCGGTT" --> "AACCGGTA"
就是一次基因变化。
另有一个基因库 bank
记录了所有有效的基因变化,只有基因库中的基因才是有效的基因序列。(变化后的基因必须位于基因库 bank
中)
给你两个基因序列 start
和 end
,以及一个基因库 bank
,请你找出并返回能够使 start
变化为 end
所需的最少变化次数。如果无法完成此基因变化,返回 -1
。
注意:起始基因序列 start
默认是有效的,但是它并不一定会出现在基因库中。
示例 1:
输入:start = "AACCGGTT", end = "AACCGGTA", bank = ["AACCGGTA"] 输出:1
示例 2:
输入:start = "AACCGGTT", end = "AAACGGTA", bank = ["AACCGGTA","AACCGCTA","AAACGGTA"] 输出:2
示例 3:
输入:start = "AAAAACCC", end = "AACCCCCC", bank = ["AAAACCCC","AAACCCCC","AACCCCCC"] 输出:3
笔记:
这道题是真抽象,对字符串进行bfs,这里的思路是:直接对字符串去处理不要讲单个字符单独处理。首先建立一个处理队列,将start加入其中,此时队列中的元素表示未处理的元素,接下来记录当前层的大小,遍历当前层的元素(只有start一个),接着对字符串进行处理,这里我们创建一个数组来存储字符可变化的样子(也就是方向数组),从当前处理的字符串的头开始向后遍历,一一替换当前遍历到的位置,如果替换后的字符串可以在bank中找到并且没有被访问过我们就将其加入que的第二层,在遍历完当前层元素后step++代表变换元素的次数。
注意:
(1)当我们向队列加入一个元素后,立即将其标记为已访问。
(2)将vector类型的bank数组改为set数组更好处理:
在一个set数组中查找元素是否存在:set.count(目标)
class Solution {
public:
int minMutation(string startGene, string endGene, vector<string>& bank) {
unordered_set<string> visited;
unordered_set<string> bank_set(bank.begin(), bank.end());
char keys[4] = {'A', 'C', 'G', 'T'};
int step = 0;
queue<string> que;
que.push(startGene);
visited.insert(startGene);
while(!que.empty()){
int size = que.size();
for(int i = 0; i < size; i++){
string cur = que.front();
que.pop();
if(cur == endGene){
return step;
}
for(int j = 0; j < cur.size(); j++){
for(int k = 0; k < 4; k++){
string next = cur;
next[j] = keys[k];
if(bank_set.count(next) && !visited.count(next)){
que.push(next);
visited.insert(next);
}
}
}
}
step++;
}
return -1;
}
};
Leetcode - 127:单词接龙
题目:
笔记:
map的插入:map<pair<string, int>> visited
visited.insert(pair<string, int> (beginWord, 1));
map的寻找:
visited.find(newword) == visited.end()
map的元素:
path = visited[word]
set的寻找:
wordset.find(endWord) == wordset.end()
(1)防止wordlist中出现多个重复的单词将其元素复制到srt容器以便后续处理
(2)我们需要提前判断当前beginword是否能够变到endword如果wordlist中没有就返回0.
(3) 我们要找的是变换到endword的所需次数,每变换一次我们就要记录变换后的单词和到这个单词所需要的步数,所以我们需要建立一个map容器一一对应。
(4)将begin加入队列,加入visted的map容器开始bfs遍历。
(5)我们需要对当前队首的单词进行操作,取出队首元素以及队首元素所对应的操作数,遍历该元素的每一个字符,将原单词复制给一个新变量,对单词进行修改,如果修改后的单词出现在wordset容器中我们就将其加入到队列和visited的map中。如果为endword则直接返回path + 1.
class Solution {
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
set<string> wordset(wordList.begin(), wordList.end());
map<string, int> visited;
if(wordset.find(endWord) == wordset.end()) return 0;
queue<string> que;
que.push(beginWord);
visited.insert(pair<string, int> (beginWord, 1));
while(!que.empty()){
string word = que.front();
que.pop();
int path = visited[word];
for(int i = 0; i < word.size(); i++){
string newword = word; // 防止改变原单词
for(int j = 0; j < 26; j++){
newword[i] = j + 'a';
if(newword == endWord) return path + 1;
if(wordset.find(newword) != wordset.end() && visited.find(newword) == visited.end()){
visited.insert(pair<string, int>(newword, path + 1));
que.push(newword);
}
}
}
}
return 0;
}
};
Leetcode - 841:钥匙与房间
题目:
笔记:
这道题就是一个遍历有向图:我们使用dfs来遍历这个有向图将访问过的房间标记,最后在检查所有房间是否全部被访问。
class Solution {
public:
void dfs(vector<vector<int>>& room, vector<bool>& visited, int x){
if(visited[x]) return;
visited[x] = true;
vector<int> keys = room[x];
for(int i = 0; i < keys.size(); i++){
dfs(room, visited, keys[i]);
}
}
bool canVisitAllRooms(vector<vector<int>>& rooms) {
vector<bool> visited(rooms.size(), false);
dfs(rooms, visited, 0);
for(int i = 0; i < rooms.size(); i++){
if(visited[i] == false) return false;
}
return true;
}
};
Leetcode - 463:岛屿的周长
题目:
笔记:
这道题就不需要在用到搜索了,当我们遇到边界或者遇到水域就对res+1即可:
class Solution {
public:
int islandPerimeter(vector<vector<int>>& grid) {
int opt[4][2] = {1,0,-1,0,0,1,0,-1};
int res = 0;
for(int i = 0; i < grid.size(); i++){
for(int j = 0; j < grid[0].size(); j++){
if(grid[i][j] == 1){
for(int k = 0; k < 4; k++){
int nextx = i + opt[k][0];
int nexty = j + opt[k][1];
if(nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size() || grid[nextx][nexty] == 0){
res++;
}
}
}
}
}
return res;
}
};