图论做题笔记:bfs

文章讨论了如何解决LeetCode问题,涉及计算从一个基因序列(start)变化到另一个基因序列(end)所需的最小基因变化次数,使用广度优先搜索(BFS)策略,考虑给定的基因库(bank)中的有效基因变化。
摘要由CSDN通过智能技术生成

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;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值