刷题 图论

面试经典 150 题 - 图

200. 岛屿数量

在这里插入图片描述

dfs 标记 visited

class Solution {
public:// dfs 染色const int direction[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};void dfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {int n = grid.size(), m = grid[0].size();visited[x][y] = true;for (int i = 0; i < 4; ++i) {int new_x = x + direction[i][0], new_y = y + direction[i][1];if (new_x < 0 || new_x >= n || new_y < 0 || new_y >= m || grid[new_x][new_y] == '0' || visited[new_x][new_y] == true) {continue;}visited[new_x][new_y] = true;dfs(grid, visited, new_x, new_y);}}int numIslands(vector<vector<char>>& grid) {int n = grid.size(), m = grid[0].size();vector<vector<bool>> visited(n, vector<bool>(m, false));int ans = 0;for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (grid[i][j] == '1' && visited[i][j] == false) {++ans;// dfs 染色 将相邻区域中的 1 全部标记为 visiteddfs(grid, visited, i, j);}}}return ans;}
};

bfs 标记 visited

class Solution {
public:// bfs 染色const int direction[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};void bfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {int n = grid.size(), m = grid[0].size();queue<pair<int,int>> que;que.push(make_pair(x, y));visited[x][y] = true;while (!que.empty()) {int cur_x = que.front().first, cur_y = que.front().second;que.pop();for (int i = 0; i < 4; ++i) {int new_x = cur_x + direction[i][0], new_y = cur_y + direction[i][1];if (new_x < 0 || new_x >= n || new_y < 0 || new_y >= m || grid[new_x][new_y] == '0' || visited[new_x][new_y] == true) {continue;}que.push(make_pair(new_x, new_y));visited[new_x][new_y] = true;}}}int numIslands(vector<vector<char>>& grid) {int n = grid.size(), m = grid[0].size();vector<vector<bool>> visited(n, vector<bool>(m, false));int ans = 0;for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (grid[i][j] == '1' && visited[i][j] == false) {++ans;// bfs 染色 将相邻区域中的 1 全部标记为 visitedbfs(grid, visited, i, j);}}}return ans;}
};

⭐️⭐️130. 被围绕的区域

从四周出发进行 bfs
在这里插入图片描述

class Solution {
public:// 想法一:// 不被围绕的区域,也即在 bfs 或者 dfs 过程中邻域中出现越界现象// 简单的想法: 在bfs 和 dfs 过程中记录所有坐标 以及 一个标志位// 如果没有出现越界,就将坐标对应的所有值赋值为 'X'// 想法二:// 更简单的想法,直接从边界上的 'O' 处出发即可,将连通域全部标记为visited// 最后遍历 visited 数组即可const int direction[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};void dfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {int n = grid.size(), m = grid[0].size();visited[x][y] = true;for (int i = 0; i < 4; ++i) {int new_x = x + direction[i][0], new_y = y + direction[i][1];if (new_x < 0 || new_x >= n || new_y < 0 || new_y >= m || grid[new_x][new_y] == 'X' || visited[new_x][new_y] == true) {continue;}visited[new_x][new_y] = true;dfs(grid, visited, new_x, new_y);}}void solve(vector<vector<char>>& grid) {int n = grid.size(), m = grid[0].size();vector<vector<bool>> visited(n, vector<bool>(m, false));for (int i = 0; i < n; ++i) {if (grid[i][0] == 'O' && visited[i][0] == false) {dfs(grid, visited, i, 0);}if (grid[i][m-1] == 'O' && visited[i][m-1] == false) {dfs(grid, visited, i, m-1);}}for (int j = 1; j < m - 1; ++j) {if (grid[0][j] == 'O' && visited[0][j] == false) {dfs(grid, visited, 0, j);}if (grid[n-1][j] == 'O' && visited[n-1][j] == false) {dfs(grid, visited, n-1, j);}}for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (grid[i][j] == 'O' && visited[i][j] == false) {grid[i][j] = 'X';}}}}
};

⭐️⭐️⭐️133. 克隆图

在这里插入图片描述

bfs 用哈希表记录节点是否访问过以及与深拷贝之间的对应关系

// 题目要求返回 图 的深拷贝
// 所谓深拷贝,也即需要新建一个节点,而不是使用原始节点,只是和原始节点的值相同
class Solution {
public:Node* cloneGraph(Node* node) {if (node == nullptr) return nullptr;Node* new_node = new Node(node->val);queue<Node*> que;unordered_map<Node*, Node*> map;que.push(node);map[node] = new_node;while (!que.empty()) {Node* cur = que.front();que.pop();for (auto next : cur->neighbors) {if (map.find(next) == map.end()) {// 出现新节点 --> 需要创建Node* new_next = new Node(next->val);que.push(next);map[next] = new_next;}map[cur]->neighbors.push_back(map[next]);}}return new_node;}
};

⭐️⭐️399. 除法求值

在这里插入图片描述

dfs 寻找可达路径

邻接矩阵和 01 矩阵的区别,一个使用 unordered_set 标记是否走过,一个使用 visited 矩阵标记是否走过

class Solution {
public:// 本题也即构建一个无向图,查找 节点之间 存在的路径// 查找路径我们可以使用 dfsstruct Edge {string node;double val;};bool dfs(string& src, string& dst, unordered_map<string, vector<Edge>>& graph, unordered_set<string>& visited, vector<double> &path) {visited.insert(src);if (src == dst) {return true;}for (auto edge : graph[src]) {if (visited.find(edge.node) == visited.end()) {path.push_back(edge.val);if (dfs(edge.node, dst, graph, visited, path)) {return true;}path.pop_back();}}return false;}vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {// 构建无向图unordered_map<string, vector<Edge>> graph;for (int i = 0; i < equations.size(); ++i) {auto& equation = equations[i];graph[equation[0]].push_back({equation[1], values[i]});graph[equation[1]].push_back({equation[0], 1.0 / values[i]});}// 遍历查询vector<double> result(queries.size(), 0);for (int i = 0; i < queries.size(); ++i) {string& src = queries[i][0], &dst = queries[i][1];if (graph.find(src) == graph.end() || graph.find(dst) == graph.end()) {result[i] = -1.0;continue;}// dfs 寻找路径vector<double> path;unordered_set<string> visited;if (dfs(src, dst, graph, visited, path)) {double ans = 1.0;for (auto p : path) {ans *= p;}result[i] = ans;} else {result[i] = -1;}}return result;}
};

207. 课程表

在这里插入图片描述

拓扑排序

class Solution {
public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {// 想法:逐个剔除入度为 0 的节点// + 如何获得每个节点的入度?// + 如何剔除节点?// prerequisites[i] = [ai, bi] 说明存在有向边 bi -> ai// 解决方案:可以用一个二维矩阵作为邻接矩阵,再用一个vector存储节点的入度vector<vector<bool>> adj(numCourses, vector<bool>(numCourses, false));vector<int> in_degree(numCourses, 0);queue<int> zero_in_nodes;for (auto& pre : prerequisites) {adj[pre[1]][pre[0]] = true;in_degree[pre[0]]++;}for (int i = 0; i < numCourses; ++i) {if (in_degree[i] == 0) {zero_in_nodes.push(i);}}while (!zero_in_nodes.empty()) {// 找到入度为0的节点int x = zero_in_nodes.front();zero_in_nodes.pop();// 删除节点for (int i = 0; i < numCourses; ++i) {if (adj[x][i]) {adj[x][i] = false;adj[i][x] = false;if (--in_degree[i] == 0) {zero_in_nodes.push(i);}}}}for (int i = 0; i < numCourses; ++i) {if (in_degree[i] > 0) {return false;}}return true;}
};

⭐️⭐️210. 课程表 II

在这里插入图片描述

class Solution {
public:// 和课程表 1 是一样的// 逐渐剔除入度为0的节点vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {vector<int> result;// 统计入度vector<int> in_degree(numCourses, 0);for (auto& prerequisite : prerequisites) {in_degree[prerequisite[1]]++;}// 统计邻接表: 删除节点的时候需要根据邻接表更新指向节点的入度vector<vector<int>> adj(numCourses);for (auto& prerequisite : prerequisites) {adj[prerequisite[0]].push_back(prerequisite[1]);}// 初始化队列,存储入度为0的节点queue<int> que;for (int i = 0; i < numCourses; ++i) {if (in_degree[i] == 0) {que.push(i);}}// 遍历队列while (!que.empty()) {// 将入度为0节点弹出队列int node_from = que.front();que.pop();result.push_back(node_from);// 根据邻接表更新入度,入度为0加入队列for (auto& node_to : adj[node_from]) {if (--in_degree[node_to] == 0) {que.push(node_to);}}}if (result.size() == numCourses) {std::reverse(result.begin(), result.end());} else {return std::vector<int>{};}return result;}
};

面试经典 150 题 - 图的广度优先搜索 - 最短路径

⭐️⭐️909. 蛇梯棋

在这里插入图片描述

bfs 最短路径长度:在队列中记录 step / 使用parent 数组

  • bfs 找最短路径 需要使用 parent数组来进行 回溯
  • 题目中的梯子和蛇 只是起到 传送作用而已,也即掷完骰子后如果到达一个梯子的起点就需要手动执行传送 next = adj[next]
class Solution {
public:int snakesAndLadders(vector<vector<int>>& board) {int n = board.size();vector<int> adj(n * n + 1, -1);// 构建 adj 数组,映射每个位置对应的蛇或梯子int label = 1;for (int i = n - 1; i >= 0; --i) {if ((n - 1 - i) % 2 == 0) {for (int j = 0; j < n; ++j) {if (board[i][j] != -1) {adj[label] = board[i][j];}++label;}} else {for (int j = n - 1; j >= 0; --j) {if (board[i][j] != -1) {adj[label] = board[i][j];}++label;}}}// BFS 进行最短路径搜索vector<bool> visited(n * n + 1, false);vector<int> parent(n * n + 1, -1);  // 记录每个节点的父节点,用于路径回溯queue<int> que;que.push(1);visited[1] = true;while (!que.empty()) {auto cur = que.front();que.pop();if (cur == n * n) { // 回溯路径int count = 0;int node = cur;while (node != 1) {++count;node = parent[node];}return count;}// 掷骰子for (int i = 1; i <= 6; ++i) {int next = cur + i;if (next > n * n) break;// 如果有梯子或蛇, 则从 next 传送到 adj[next]if (adj[next] != -1) {next = adj[next];}if (!visited[next]) {visited[next] = true;parent[next] = cur;  // 记录父节点que.push(next);}}}return -1;  // 无法到达终点}
};

⭐️⭐️433. 最小基因变化

在这里插入图片描述

bfs 最短路径长度:在队列中记录 step

class Solution {
public:bool check(string& s1, string& s2) {int count = 0;for (int i = 0; i < s1.size(); ++i) {count += (s1[i] != s2[i]);if (count > 1) {return false;}}return true;}// 起始序列不一定在bank中int minMutation(string startGene, string endGene, vector<string>& bank) {// 先检查一下终止序列是否在bank中int n = bank.size();int src = -1, dst = -1;for (int i = 0; i < n; ++i) {if (bank[i] == endGene) {dst = i;}if (bank[i] == startGene) {src = i;}}if (dst == -1) return -1;if (src == -1) src = n;// 构建邻接表vector<vector<int>> adj(n + 1);// src 到 bank 是单向的if (src == n) {for (int i = 0; i < n; ++i) {if (check(startGene, bank[i])) {adj[n].push_back(i);}}}for (int i = 0; i < n - 1; ++i) {for (int j = i + 1; j < n; ++j) {if (check(bank[i], bank[j])) {adj[i].push_back(j);adj[j].push_back(i);}}}// bfs 搜索路径长度vector<bool> visited(n + 1, false);queue<pair<int, int>> que;que.push({src, 0});visited[src] = true;while (!que.empty()) {auto [cur, step] = que.front();if (cur == dst) {return step;}que.pop();for (auto& next : adj[cur]) {if (visited[next] == false) {que.push({next, step + 1});visited[next] = true;}}}return -1;}
};

双向bfs:两边分别使用一个visited数组记录path长度,根据两个visited数组来判断是否,优先扩展较小的搜索方向

通过设置条件,当某一方向的队列长度显著小于另一方向时,可以优先展开该方向的搜索,避免不必要的广度扩展。

class Solution {
public:bool check(const string& s1, const string& s2) {int count = 0;for (int i = 0; i < s1.size(); ++i) {if (s1[i] != s2[i] && ++count > 1) {return false;}}return true;}int minMutation(string startGene, string endGene, vector<string>& bank) {int n = bank.size();int src = -1, dst = -1;// 提前记录起点和终点for (int i = 0; i < n; ++i) {if (bank[i] == endGene) dst = i;if (bank[i] == startGene) src = i;}if (dst == -1) return -1;if (src == -1) src = n;  // 起始序列不在 bank 中// 构建邻接表,减少不必要的 check 调用vector<vector<int>> adj(n + 1);if (src == n) {for (int i = 0; i < n; ++i) {if (check(startGene, bank[i])) {adj[n].push_back(i);}}}for (int i = 0; i < n; ++i) {for (int j = i + 1; j < n; ++j) {if (check(bank[i], bank[j])) {adj[i].push_back(j);adj[j].push_back(i);}}}// 使用双向 BFSvector<int> visited_forward(n + 1, -1);vector<int> visited_back(n + 1, -1);queue<pair<int, int>> que_forward;queue<pair<int, int>> que_back;que_forward.push({src, 0});que_back.push({dst, 0});visited_forward[src] = 0;visited_back[dst] = 0;// 优化 BFS 方向的扩展while (!que_forward.empty() && !que_back.empty()) {// 优先扩展较小的搜索方向if (que_forward.size() <= que_back.size()) {auto [cur, steps] = que_forward.front();que_forward.pop();for (int next : adj[cur]) {if (visited_forward[next] == -1) {visited_forward[next] = steps + 1;if (visited_back[next] != -1) {return visited_forward[next] + visited_back[next];}que_forward.push({next, steps + 1});}}} else {auto [cur, steps] = que_back.front();que_back.pop();for (int next : adj[cur]) {if (visited_back[next] == -1) {visited_back[next] = steps + 1;if (visited_forward[next] != -1) {return visited_forward[next] + visited_back[next];}que_back.push({next, steps + 1});}}}}return -1;}
};

127. 单词接龙

在这里插入图片描述

和最小基因变化是一样的,只不过长度需要加1,不成立的话返回0而不是-1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/444360.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET NoSQL 嵌入式数据库 LiteDB 使用教程

前言 今天大姚给大家分享一个小巧、快速、轻量级的.NET 开源且免费&#xff08;MIT License&#xff09;的 NoSQL 嵌入式数据库&#xff1a;LiteDB。本篇文章我们主要来讲讲LiteDB在.NET中如何使用。 LiteDB介绍 LiteDB 是一个小巧、快速和轻量级的 .NET NoSQL 嵌入式数据库…

什么是快充协议、支持多协议的USB Type-C受电端取电芯片

随着快充技术的不断发展&#xff0c;传统的慢充模式已经满足不了消费者对充电效率的要求。有了快充技术的支持很大程度的缩短了我们的充电时间&#xff0c;给我们的生活带来了很多便利。 什么是快充协议 快充协议是快充技术的核心&#xff0c;现如今市面上已经有很多种快充协议…

打破常规,BD仓储物流的效能提升!

当前&#xff0c;随着国家战略的推进&#xff0c;JS与民用领域的融合不断加深&#xff0c;物流业也步入了军民融合的新时代。在智能仓储物流方面&#xff0c;JS物流的智能化进展受到了BD系统的高度关注和重视。 一、建设JS仓储物流RFID基础设施 JS物流领域引入RFID技术的基础工…

代码随想录算法训练营Day31 | 455.分发饼干、376.摆动序列、53.最大子数组和

目录 455.分发饼干 376.摆动序列 53.最大子数组和 455.分发饼干 题目 455. 分发饼干 - 力扣&#xff08;LeetCode&#xff09; 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c…

论文翻译 | Fairness-guided Few-shot Prompting for LargeLanguage Models

摘要 大型语言模型已经显示出令人惊讶的执行上下文学习的能力&#xff0c;也就是说&#xff0c;这些模型可以通过对由几个输入输出示例构建的提示进行条件反射&#xff0c;直接应用于解决大量下游任务。然而&#xff0c;先前的研究表明&#xff0c;由于训练示例、示例顺序和提示…

HTML的介绍

HTML HTML是一种超文本标记语言,超文本是指,除了文本之外,还可能包含图片,音频,或者评注等的 文本形式,比文本强大,通过链接和交互方式来组织和呈现信息.标记语言是指,由标签构成的语言.HTML定义了多种不同的标签,用来表示不同的内容. 标签的介绍: 1.<h3> 三级 </h3&…

java多态-cnblog

java多态 细分的重载会增加代码量&#xff0c;降低易用程度 定义一个类&#xff0c;继承所有类的对象&#xff0c;根据向上转型可以让每个类的对象都调用初始类的方法&#xff0c;在方法中设置判断&#xff0c;不同的对象导致方法做不同的事&#xff0c;这就是多态 写一个灯…

视频监控汇聚平台Liveweb安防监控平台实现接入监控视频集中管理方案

随着各行业数字化转型的不断推进&#xff0c;视频监控技术在行业内的安防应用及管理支撑日益增多。然而&#xff0c;由于前期规划不清晰、管理不到位等问题&#xff0c;视频监管系统普遍存在以下问题&#xff1a; 1. 各部门单位在视频平台建设中以所属领域为单位&#xff0c;导…

博客项目自动化测试(一)

1. 确认博客系统的环境搭建 http://49.235.129.183:8080/java109_blog_system/blog_list.html&#xff0c;即可访问我的小项目&#xff1b; 2. 确定测试用例 测试用例如下所示&#xff1a; 3. 关于登录的测试用例 3.1 初始化和退出浏览器 代码如下&#xff1a; package Blo…

《大道平渊》· 廿贰 —— 杀心篇:独立人格的形成

《大道平渊》 独立人格的形成&#xff0c;在杀心的过程中会越来越完备。 在这个漫长的过程中&#xff0c;你会一次次击碎自己固有的三观&#xff0c;慢慢再修复你的三观。 . 不要认为一个人的明白&#xff0c;都是恍然大悟&#xff0c;都是碰到了高人指点。 并不是这样的&a…

面试还搞不懂redis,快看看这40道面试题

Redis 面试题 1、什么是 Redis?. 2、Redis 的数据类型&#xff1f; 3、使用 Redis 有哪些好处&#xff1f; 4、Redis 相比 Memcached 有哪些优势&#xff1f; 5、Memcache 与 Redis 的区别都有哪些&#xff1f; 6、Redis 是单进程单线程的&#xff1f; 7、一个字符串类…

python安装插件

报错 E:\pythonProject\pythonProject_JD\Scripts\python.exe E:\浏览器下载\pythoncode\pythonProject_JD\car.py Traceback (most recent call last): File "E:\浏览器下载\pythoncode\pythonProject_JD\car.py", line 5, in <module> from selenium…

双向数据库迁移工具:轻松实现 MySQL 与 SQLite 数据互导

项目概述与作用 该项目的核心是实现 MySQL 和 SQLite 两种数据库之间的数据迁移工具。它能够轻松地将 MySQL 数据库中的数据导出为 SQLite 数据库文件&#xff0c;反过来也可以将 SQLite 数据库中的数据上传到 MySQL 数据库中。这个双向迁移工具非常适用于&#xff1a; 数据库备…

LeetCode15.三数之和

题目链接&#xff1a;15. 三数之和 - 力扣&#xff08;LeetCode&#xff09; 1.常规解法&#xff08;会超时&#xff09; 由于这道题需要排除相同的三元组&#xff0c;则可以先将目标数组从小到大排序&#xff0c;再遍历数组找到每个符合条件的三元组&#xff0c;若结果中不包…

2.JVM性能调优之JVM内存模型深度剖析与优化

1 JDK体系结构 2 Java语言的跨平台特性 3 JVM整体结构及内存模型 3.1 堆内存划分 public class Demo {public static void main(String[] args) {Demo demo new Demo();int rs demo.compute();System.out.println(rs);}public int compute() {int a 1;int b 3;int c (a b…

01 为什么要学习数据结构与算法

为什么要学习数据结构与算法 一、问题提出 ​ 最早计算机的设计初衷主要用于军事上枪炮的弹道计算和火力表的测试&#xff0c;后来更多的用于科学计算&#xff0c;即数值类的计算&#xff0c;而现在&#xff0c;计算机深入到日常生活的各个方面&#xff0c;其计算的数据早已从…

博客搭建之路:Netlify将url重定向到小写问题

文章目录 Netlify将url重定向到小写问题 Netlify将url重定向到小写问题 hexo版本5.0.2 npm版本6.14.7 next版本7.8.0 前两天将博客从vercel改为托管到Netlify上&#xff0c;本来运行的挺流畅的。但是今天我看一篇博客的评论时突然发现&#xff0c;虽然有评论 但是文章开头的评论…

【正点原子K210连载】第四十三章 人脸属性分析实验 摘自【正点原子】DNK210使用指南-CanMV版指南

第四十三章 人脸属性分析实验 在上一章节中&#xff0c;介绍了利用maix.KPU模块实现了人脸口罩佩戴检测&#xff0c;本章将继续介绍利用maix.KPU模块实现的人脸属性分析。通过本章的学习&#xff0c;读者将学习到人脸属性分析应用在CanMV上的实现。 本章分为如下几个小节&…

JUC高并发编程10:线程池

1 线程池概述 1.1 线程池简介 线程池&#xff08;Thread Pool&#xff09;是一种线程使用模式。在多线程编程中&#xff0c;线程的创建和销毁会带来一定的开销&#xff0c;尤其是在处理大量短时间任务时&#xff0c;频繁的线程创建和销毁会导致调度开销增加&#xff0c;进而影…

Java 集合 Collection常考面试题

理解集合体系图 collection中 list 是有序的,set 是无序的 什么是迭代器 主要遍历 Collection 集合中的元素,所有实现了 Collection 的集合类都有一个iterator()方法,可以返回一个 iterator 的迭代器。 ArrayList 和 Vector 的区别? ArrayList 可以存放 null,底层是由数…