力扣第841题 钥匙和房间 C++ DFS BFS 附Java代码

题目

841. 钥匙和房间

中等

相关标签

深度优先搜索   广度优先搜索  图

有 n 个房间,房间按从 0 到 n - 1 编号。最初,除 0 号房间外的其余所有房间都被锁住。你的目标是进入所有的房间。然而,你不能在没有获得钥匙的时候进入锁住的房间。

当你进入一个房间,你可能会在里面找到一套不同的钥匙,每把钥匙上都有对应的房间号,即表示钥匙可以打开的房间。你可以拿上所有钥匙去解锁其他房间。

给你一个数组 rooms 其中 rooms[i] 是你进入 i 号房间可以获得的钥匙集合。如果能进入 所有 房间返回 true,否则返回 false

示例 1:

输入:rooms = [[1],[2],[3],[]]
输出:true
解释:
我们从 0 号房间开始,拿到钥匙 1。
之后我们去 1 号房间,拿到钥匙 2。
然后我们去 2 号房间,拿到钥匙 3。
最后我们去了 3 号房间。
由于我们能够进入每个房间,我们返回 true。

示例 2:

输入:rooms = [[1,3],[3,0,1],[2],[0]]
输出:false
解释:我们不能进入 2 号房间。

提示:

  • n == rooms.length
  • 2 <= n <= 1000
  • 0 <= rooms[i].length <= 1000
  • 1 <= sum(rooms[i].length) <= 3000
  • 0 <= rooms[i][j] < n
  • 所有 rooms[i] 的值 互不相同

思路和解题方法  深度优先搜索 

  1. 首先是 dfs 函数:

    • 这个函数使用深度优先搜索(DFS)来模拟访问房间和获取钥匙的过程。
    • 它接受三个参数:rooms 代表房间及其对应的钥匙信息的二维数组,key 代表当前要访问的房间号,visited 代表记录房间访问状态的布尔数组。
    • 函数首先检查当前房间是否已经访问过,如果是,则直接返回,避免重复访问;否则将当前房间标记为已访问,并获取当前房间中的钥匙信息。
    • 然后对每把钥匙都进行深度优先搜索,即递归调用 dfs 函数,以访问新房间并获取新房间中的钥匙。
  2. 接下来是 canVisitAllRooms 函数:

    • 这个函数判断是否可以访问所有房间。
    • 首先初始化了一个布尔数组 visited,用于记录各个房间的访问状态,初始值为 false 表示未访问。
    • 然后调用了 dfs 函数,从第一个房间开始进行深度优先搜索,以尝试访问所有可以到达的房间。
    • 最后遍历 visited 数组,如果有任意一个房间未被访问,则返回 false,表示无法访问所有房间;否则返回 true,表示可以成功访问所有房间。

复杂度

        时间复杂度:

                O(n+k)

时间复杂度取决于房间数量和钥匙数量,假设有 n 个房间和 k 个钥匙。在最坏情况下,每个房间都需要被访问一次,并且每个钥匙都需要被尝试使用一次。因此,时间复杂度为 O(n+k)。

        空间复杂度

                O(n)

至于空间复杂度,主要是由递归调用的深度决定的,最坏情况下可能需要 O(n) 的栈空间。此外,还需使用一个大小为 n 的布尔数组来记录各个房间的访问状态,因此整体空间复杂度为 O(n)。

c++ 代码  1

class Solution {
public:// 深度优先搜索函数,用于访问房间和相关钥匙void dfs(vector<vector<int>> &rooms, int key, vector<bool> &visited) {// 如果当前钥匙已经被访问过,则直接返回if (visited[key]) {return;}visited[key] = true; // 标记当前钥匙为已访问vector<int> keys = rooms[key]; // 获取当前房间中的钥匙for (int nextKey : keys) {dfs(rooms, nextKey, visited); // 对每把钥匙进行深度优先搜索}}// 判断是否能访问所有房间bool canVisitAllRooms(vector<vector<int>>& rooms) {vector<bool> visited(rooms.size(), false); // 初始化访问状态数组dfs(rooms, 0, visited); // 从第一个房间开始进行深度优先搜索// 检查是否所有房间都被访问过for (bool visit : visited) {if (!visit) {return false; // 如果有任意一个房间未被访问,则返回false}}return true; // 所有房间都被访问过,返回true}
};

思路和解题方法  广度优先搜索 

  1. 首先是 dfs 函数:

    • 这个函数使用深度优先搜索(DFS)来模拟访问房间和获取钥匙的过程。
    • 它接受三个参数:rooms 代表房间及其对应的钥匙信息的二维数组,key 代表当前要访问的房间号,visited 代表记录房间访问状态的布尔数组。
    • 函数首先检查当前房间是否已经访问过,如果是,则直接返回,避免重复访问;否则将当前房间标记为已访问,并获取当前房间中的钥匙信息。
    • 然后对每把钥匙都进行深度优先搜索,即递归调用 dfs 函数,以访问新房间并获取新房间中的钥匙。
  2. 接下来是 canVisitAllRooms 函数:

    • 这个函数判断是否可以访问所有房间。
    • 首先初始化了一个布尔数组 visited,用于记录各个房间的访问状态,初始值为 false 表示未访问。
    • 然后调用了 dfs 函数,从第一个房间开始进行深度优先搜索,以尝试访问所有可以到达的房间。
    • 最后遍历 visited 数组,如果有任意一个房间未被访问,则返回 false,表示无法访问所有房间;否则返回 true,表示可以成功访问所有房间。

复杂度

        时间复杂度:

                O(n^2)

时间复杂度分析:

  • 在最坏情况下,每个房间都需要被访问一次,因此广度优先搜索的时间复杂度为 O(n),其中 n 为房间的数量。
  • 对于每个房间,我们需要遍历其对应的钥匙列表,这一步的时间复杂度也是 O(n),因为在最坏情况下,每个房间都有 n 个钥匙。
  • 因此总体时间复杂度为 O(n^2)。

        空间复杂度

                O(n)

空间复杂度分析:

  • visited 数组占用了 O(n) 的额外空间,用于标记每个房间是否被访问过。
  • 队列 que 最大可能包含 n 个元素,因此队列的空间复杂度也是 O(n)。
  • 因此总体空间复杂度为 O(n)。

c++ 代码  2

class Solution {bool bfs(const vector<vector<int>>& rooms) {vector<int> visited(rooms.size(), 0); // 用于标记房间是否被访问过,初始值都为 0visited[0] = 1; // 从 0 号房间开始访问,将 0 号房间标记为已访问queue<int> que;que.push(0); // 将 0 号房间加入队列,表示从这里开始访问// 广度优先搜索的过程while (!que.empty()) {int key = que.front(); que.pop(); // 取出队列中的下一个要访问的房间号vector<int> keys = rooms[key]; // 获取当前房间中的钥匙信息for (int nextKey : keys) { // 遍历当前房间的钥匙,尝试打开新的房间if (!visited[nextKey]) { // 如果遇到未访问过的房间que.push(nextKey); // 将该房间加入队列,表示要访问这个房间visited[nextKey] = 1; // 并标记该房间为已访问}}}// 检查房间是不是都遍历过了for (int i : visited) {if (i == 0) return false; // 如果有任意一个房间未被访问,则返回 false}return true; // 否则返回 true,表示所有房间都被成功访问了}public:bool canVisitAllRooms(vector<vector<int>>& rooms) {return bfs(rooms); // 调用 bfs 函数进行广度优先搜索,判断是否可以访问所有房间}
};

Java双代码

DFS

class Solution {// 使用深度优先搜索来访问房间private void dfs(int key, List<List<Integer>> rooms, List<Boolean> visited) {// 如果当前房间已经访问过,则直接返回if (visited.get(key)) {return;}// 将当前房间标记为已访问visited.set(key, true);// 遍历当前房间中的钥匙,继续深度优先搜索for (int k : rooms.get(key)) {dfs(k, rooms, visited);}}// 判断是否可以访问所有房间public boolean canVisitAllRooms(List<List<Integer>> rooms) {// 初始化一个列表来记录每个房间是否被访问过List<Boolean> visited = new ArrayList<Boolean>(){{// 初始化为 false,表示所有房间都未被访问过for(int i = 0 ; i < rooms.size(); i++){add(false);}}};// 从 0 号房间开始深度优先搜索dfs(0, rooms, visited);// 检查是否所有房间都被访问过for (boolean flag : visited) {if (!flag) {return false; // 如果有任意一个房间未被访问,则返回 false}}return true; // 否则返回 true,表示所有房间都被成功访问了}
}

BFS

class Solution {public boolean canVisitAllRooms(List<List<Integer>> rooms) {boolean[] visited = new boolean[rooms.size()]; // 用一个 boolean 数组记录房间是否被访问visited[0] = true; // 标记第 0 个房间为已访问Queue<Integer> queue = new ArrayDeque<>(); // 创建一个队列用于广度优先搜索queue.add(0); // 将第 0 个房间加入队列,表示从该房间开始访问其他房间while (!queue.isEmpty()) {int curKey = queue.poll(); // 取出队首房间// 遍历当前房间中的钥匙,标记并加入队列for (int key : rooms.get(curKey)) {if (visited[key]) continue; // 如果房间已经访问过,则继续下一次循环visited[key] = true; // 标记该房间为已访问queue.add(key); // 将该房间加入队列,表示将从该房间开始继续访问其他房间}}// 检查是否所有房间都被访问过for (boolean key : visited) {if (!key) {return false; // 如果有任意一个房间未被访问,则返回 false}}return true; // 否则返回 true,表示所有房间都被成功访问了}
}

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

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

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

相关文章

【MISRA C 2012】Rule 4.2 不应该使用三连符

1. 规则1.1 原文1.2 分类 2. 关键描述3. 代码实例 1. 规则 1.1 原文 Rule 4.2 Trigraphs should not be used Category Advisory Analysis Decidable, Single Translation Unit Applies to C90, C99 1.2 分类 规则4.2&#xff1a;不应该使用三连符 Advisory建议类规范。 2…

Leetcode—5.最长回文子串【中等】

2023每日刷题&#xff08;三十五&#xff09; Leetcode—5.最长回文子串 中心扩展法算法思想 可以使用一种叫作“中心扩展法”的算法。由回文的性质可以知道&#xff0c;回文一定有一个中心点&#xff0c;从中心点向左和向右所形成的字符序列是一样的&#xff0c;并且如果字符…

Rust宏详解之类函数宏

文章目录 过程宏类函数宏调用与测试 Rust基础教程&#xff1a;初步⚙所有权⚙结构体和枚举类⚙函数进阶⚙泛型和特征⚙并发和线程通信⚙cargo包管理 Rust进阶教程&#xff1a;用宏实现参数可变的函数 过程宏 在Rust中&#xff0c;macro_rules!是最常用的宏&#xff0c;也叫声…

11.1 文件拷贝移动与删除

在编程中&#xff0c;针对磁盘与目录的操作也是非常重要的&#xff0c;本章将重点介绍如何实现针对文件目录与磁盘的操作方法&#xff0c;其中包括了删除文件&#xff0c;文件拷贝&#xff0c;文件读写&#xff0c;目录遍历输出&#xff0c;遍历磁盘容量信息&#xff0c;磁盘格…

Vue移动 HTML 元素到指定位置 teleport 标签

teleport 标签&#xff1a;用于将组件中的 HTML 元素移动到任意的位置。 使用 teleport 标签移动 HTML 元素&#xff1a; <!-- 将 teleport 中的内容移动到 body 标签中 --> <teleport to"body"><div><h3>我是第三层组件的标题</h3>…

如何使用http来获取thingsbord中的设备数据

背景 有个读者问我,他想做tb的二次开发,想要通过一个接口来查询设备的遥测数据。 于是我给他写了这篇文章。 具体实现 由于他使用的是cloud版本,于是我使用cloud来做演示 文档的接口 https://thingsboard.cloud/swagger-ui/#/telemetry-controller/getTimeseriesUsing…

数据结构【DS】队列的应用

描述一下如何进行层次遍历&#xff1f; 创建一个空队列&#xff0c;将根节点入队&#xff1b;循环执行以下步骤&#xff0c;直到队列为空&#xff1a; 取出队头结点访问该结点将该结点的所有子节点入队 在计算机系统中的应用 解决主机与外部设备之间速度不匹配的问题&#xf…

react经典面试题解析

一、类组件和函数组件的区别&#xff08;面试常考&#xff09; 简单理解&#xff08;所有同学都要掌握&#xff09; 1、类组件有生命周期&#xff0c;函数组件没有 2、类组件需要继承 Class&#xff0c;函数组件不需要 3、类组件可以获取实例化的 this&#xff0c;并且基于…

V100 GPU服务器安装CUDA教程

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Linux C 线程间同步机制

线程间同步机制 概述保护机制互斥锁创建互斥锁  pthread_mutex_init加锁  pthread_mutex_lock解锁  pthread_mutex_unlock删除锁  pthread_mutex_destroy 条件变量创建条件变量  pthread_cond_init激活条件变量  pthread_cond_signal等待条件变量  pthread_cond_…

python实现炫酷的屏幕保护程序

shigen日更文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 上次的文章如何实现一个下班倒计时程序的阅读量很高&#xff0c;觉得也很实用酷炫&#xff0c;下边是昨天的体验…

2216.美化数组的最少删除数

​​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;2216. 美化数组的最少删除数 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 假设在第 i 个位置前已删除 res 个元素。遍历原数组&#xff0c;对于第 i 个元素&#xff0c;若 (i-res)%20&am…

shell 判断文件是否存在(csh bash)

文章目录 前言1. -e 判断文件是否存在2. -f 判断文件是否存在且为普通文件3. -d 判断文件是否存在且为目录3. -s 判断文件是否存在且不为空4. -r 判断文件是否存在且可读5. -w 判断文件是否存在且可写6. -x 判断文件是否存在且可执行 前言 Shell 编程能提升我们工作效率&#…

QT5 MSVC2017 64bit配置OpenCV4.5无需编译与示范程序

环境&#xff1a;Windows 10 64位 Opencv版本&#xff1a;4.5 QT&#xff1a;5.14 QT5 MSVC2017配置OpenCV 版本参考&#xff1a; opencv msvc c对应版本 1.安装MSVC2017&#xff08;vs2017&#xff09; 打开Visual Studio Installer&#xff0c;点击修改 选择vs2017生成工…

java使用 TCP 的 Socket API 实现客户端服务器通信

一&#xff1a;什么是 Socket(套接字) Socket 套接字是由系统提供于网络通信的技术, 是基于 TCP/IP 协议的网络通信的基本操作&#xff0c;要进行网络通信, 需要有一个 socket 对象, 一个 socket 对象对应着一个 socket 文件, 这个文件在 网卡上而不是硬盘上, 所以有了 sokcet…

3D应用开发引擎HOOPS如何促进AEC数字化架构革新?

随着科技的不断发展&#xff0c;建筑、工程和施工&#xff08;AEC&#xff09;行业正在掀起令人瞩目的数字化转型浪潮。在这一变革的过程中&#xff0c;Tech Soft 3D的HOOPS SDK&#xff08;软件开发工具包&#xff09;正扮演着关键的角色&#xff0c;为构建世界一流的AEC和BIM…

【CVE-2023-4357】Chrome-XXE 任意文件读取漏洞复现及原理解析

官方文档 https://bugs.chromium.org/p/chromium/issues/detail?id1458911 漏洞描述 Short description: Libxslt is the default XSL library used in WebKit based browsers such as chrome, safari etc. Libxslt allows external entities inside documents that are lo…

UML统一建模语言

UML包含3种构造块&#xff1a;事物、关系、图。 事物&#xff1a;模型中代表性成分的抽象关系&#xff1a;把事物结合在一起图&#xff1a;聚集了相关的事物 事物 结构事务&#xff1a;模型的静态部分&#xff0c;包括类、接口、协作、用例、主动类、构件、制品、结点 行为事…

ubuntu 解决pip/pip3安装库各种报错问题

诸如下面类似的报错: 都是由于pip损坏导致 File “/usr/local/bin/pip3”, line 7, in from pip._internal.cli.main import main File “/usr/local/lib/python3.5/dist-packages/pip/_internal/cli/main.py”, line 57 sys.stderr.write(f"ERROR: {exc}") 解绝办法…

py split 用法

在Python中&#xff0c;split()函数用于将字符串按照指定的分隔符进行分割&#xff0c;并返回一个字符串列表。它的基本用法如下&#xff1a; string "Hello, World!" split_string string.split(",") print(split_string)输出结果为&#xff1a; [Hel…