当前位置: 首页 > news >正文

算法题 钥匙和房间

841. 钥匙和房间

问题描述

n个房间,编号从0n-1。每个房间都有一些钥匙,可以打开其他房间。

给定一个数组rooms,其中rooms[i]是一个列表,表示你进入房间i后可以拿到的所有钥匙(钥匙对应房间的编号)。

你从房间0开始,初始时可以进入房间0

返回true如果你可以进入所有房间,否则返回false

示例

输入:rooms=[[1],[2],[3],[]]输出:true解释:-从房间0开始,拿到钥匙1-用钥匙1进入房间1,拿到钥匙2-用钥匙2进入房间2,拿到钥匙3-用钥匙3进入房间3-所有房间都已访问
输入:rooms=[[1,3],[3,0,1],[2],[0]]输出:false解释:-从房间0开始,拿到钥匙13-可以进入房间13,但无法进入房间2-房间2中有钥匙2,但无法获得

算法思路

图的遍历(DFS/BFS)

  1. 建模

    • 将房间看作图的节点,钥匙看作有向边
    • 问题转化为:从节点0出发,能否访问所有节点?
  2. 遍历

    • DFS(深度优先搜索):递归或栈实现
    • BFS(广度优先搜索):队列实现

代码实现

方法一:DFS递归

importjava.util.*;classSolution{/** * 判断是否能进入所有房间 * 使用DFS递归遍历,从房间0开始 * * @param rooms 房间钥匙信息,rooms[i]表示房间i中的钥匙列表 * @return 如果能进入所有房间返回true,否则返回false */publicbooleancanVisitAllRooms(List<List<Integer>>rooms){intn=rooms.size();boolean[]visited=newboolean[n];// 记录房间访问状态// 从房间0开始DFSdfs(rooms,0,visited);// 检查是否所有房间都被访问for(booleanroomVisited:visited){if(!roomVisited){returnfalse;}}returntrue;}/** * 深度优先搜索遍历房间 * * @param rooms 房间钥匙信息 * @param room 当前房间编号 * @param visited 访问状态数组 */privatevoiddfs(List<List<Integer>>rooms,introom,boolean[]visited){// 标记当前房间为已访问visited[room]=true;// 遍历当前房间中的所有钥匙for(intkey:rooms.get(room)){// 如果对应的房间未访问过,递归访问if(!visited[key]){dfs(rooms,key,visited);}}}}

方法二:DFS栈实现

importjava.util.*;classSolution{/** * 使用栈实现DFS遍历 */publicbooleancanVisitAllRooms(List<List<Integer>>rooms){intn=rooms.size();boolean[]visited=newboolean[n];Stack<Integer>stack=newStack<>();// 从房间0开始stack.push(0);visited[0]=true;intvisitedCount=1;// 已访问房间数while(!stack.isEmpty()){intcurrentRoom=stack.pop();// 遍历当前房间的所有钥匙for(intkey:rooms.get(currentRoom)){if(!visited[key]){visited[key]=true;stack.push(key);visitedCount++;// 如果已经访问了所有房间,提前结束if(visitedCount==n){returntrue;}}}}returnvisitedCount==n;}}

方法三:BFS队列实现

importjava.util.*;classSolution{/** * 使用BFS(队列)实现遍历 */publicbooleancanVisitAllRooms(List<List<Integer>>rooms){intn=rooms.size();boolean[]visited=newboolean[n];Queue<Integer>queue=newLinkedList<>();// 从房间0开始queue.offer(0);visited[0]=true;intvisitedCount=1;while(!queue.isEmpty()){intcurrentRoom=queue.poll();// 遍历当前房间的所有钥匙for(intkey:rooms.get(currentRoom)){if(!visited[key]){visited[key]=true;queue.offer(key);visitedCount++;// 提前结束if(visitedCount==n){returntrue;}}}}returnvisitedCount==n;}}

方法四:使用Set记录访问状态

importjava.util.*;classSolution{/** * 使用Set记录已访问房间 */publicbooleancanVisitAllRooms(List<List<Integer>>rooms){Set<Integer>visited=newHashSet<>();Stack<Integer>stack=newStack<>();stack.push(0);while(!stack.isEmpty()){introom=stack.pop();visited.add(room);for(intkey:rooms.get(room)){if(!visited.contains(key)){stack.push(key);}}}returnvisited.size()==rooms.size();}}

算法分析

  • 时间复杂度:O(N + K)
    • N 是房间数量
    • K 是所有钥匙的总数(图中边的数量)
    • 每个房间和每把钥匙最多被访问一次
  • 空间复杂度:O(N)
    • visited数组:O(N)
    • 递归栈/显式栈/队列:最坏情况下 O(N)
    • 总体空间复杂度为 O(N)

算法过程

1:rooms = [[1],[2],[3],[]]

DFS递归过程

  1. 访问房间0visited = [true, false, false, false]

    • 钥匙:[1]
    • 递归访问房间1
  2. 访问房间1visited = [true, true, false, false]

    • 钥匙:[2]
    • 递归访问房间2
  3. 访问房间2visited = [true, true, true, false]

    • 钥匙:[3]
    • 递归访问房间3
  4. 访问房间3visited = [true, true, true, true]

    • 钥匙:[]
    • 返回
  5. 检查结果:所有房间都已访问 →true

2:rooms = [[1,3],[3,0,1],[2],[0]]

DFS递归过程

  1. 访问房间0visited = [true, false, false, false]

    • 钥匙:[1, 3]
    • 先递归访问房间1
  2. 访问房间1visited = [true, true, false, false]

    • 钥匙:[3, 0, 1]
    • 房间3未访问,递归访问房间3
    • 房间0和1已访问,跳过
  3. 访问房间3visited = [true, true, false, true]

    • 钥匙:[0]
    • 房间0已访问,跳过
    • 返回到房间1,再返回到房间0
  4. 回到房间0:处理钥匙3(已访问),结束

  5. 检查结果visited = [true, true, false, true],房间2未访问 →false

测试用例

importjava.util.*;publicclassMain{publicstaticvoidmain(String[]args){Solutionsolution=newSolution();// 测试用例1:可以访问所有房间List<List<Integer>>rooms1=Arrays.asList(Arrays.asList(1),Arrays.asList(2),Arrays.asList(3),Arrays.asList());System.out.println("Test 1: "+solution.canVisitAllRooms(rooms1));// true// 测试用例2:无法访问所有房间List<List<Integer>>rooms2=Arrays.asList(Arrays.asList(1,3),Arrays.asList(3,0,1),Arrays.asList(2),Arrays.asList(0));System.out.println("Test 2: "+solution.canVisitAllRooms(rooms2));// false// 测试用例3:只有一个房间List<List<Integer>>rooms3=Arrays.asList(Arrays.asList());System.out.println("Test 3: "+solution.canVisitAllRooms(rooms3));// true// 测试用例4:两个房间,互相有钥匙List<List<Integer>>rooms4=Arrays.asList(Arrays.asList(1),Arrays.asList(0));System.out.println("Test 4: "+solution.canVisitAllRooms(rooms4));// true// 测试用例5:两个房间,单向有钥匙List<List<Integer>>rooms5=Arrays.asList(Arrays.asList(1),Arrays.asList());System.out.println("Test 5: "+solution.canVisitAllRooms(rooms5));// true// 测试用例6:两个房间,没有钥匙List<List<Integer>>rooms6=Arrays.asList(Arrays.asList(),Arrays.asList());System.out.println("Test 6: "+solution.canVisitAllRooms(rooms6));// false// 测试用例7:复杂情况List<List<Integer>>rooms7=Arrays.asList(Arrays.asList(1,2,3),Arrays.asList(2,3),Arrays.asList(3),Arrays.asList());System.out.println("Test 7: "+solution.canVisitAllRooms(rooms7));// true// 测试用例8:环形结构List<List<Integer>>rooms8=Arrays.asList(Arrays.asList(1),Arrays.asList(2),Arrays.asList(0));System.out.println("Test 8: "+solution.canVisitAllRooms(rooms8));// true// 测试用例9:多个分支List<List<Integer>>rooms9=Arrays.asList(Arrays.asList(1,2),Arrays.asList(3),Arrays.asList(4),Arrays.asList(),Arrays.asList());System.out.println("Test 9: "+solution.canVisitAllRooms(rooms9));// true}}

关键点

  1. 图遍历

    • 房间是节点,钥匙是有向边
    • 问题等价于判断从节点0出发是否能到达所有节点
  2. 起始条件

    • 保证可以从房间0开始(不需要钥匙)
    • 这是连通性判断的起点
  3. 访问标记

    • 避免重复访问和无限循环
    • 环形结构(如房间0→1→2→0)需要正确处理

常见问题

  1. 为什么不需要考虑钥匙的使用顺序?
    能否访问所有房间,而不是访问的顺序。只要存在一条路径能到达某个房间,就认为可以访问。

  2. DFS和BFS有什么区别?
    在这个问题中,两种方法的结果完全相同。DFS可能会更快到达某些房间,BFS按层次访问,最终的可达性判断是一样的。

http://www.jsqmd.com/news/134685/

相关文章:

  • 2025香港必备专业的人力资源服务商:Safeguard Global名义雇主深度测评 - 品牌2025
  • 为什么顶尖团队都在抢用智普Open-AutoGLM国内镜像?真相令人震惊
  • 智谱AutoGLM平台接入指南:5步实现模型自动化训练与部署
  • 视频直播点播平台EasyDSS重塑远程会议直播新体验
  • 必藏副业干货!SRC 漏洞挖掘思路手法深度讲解(超详尽),零基础直达精通,一篇就够用
  • AI定价战:Gemini 3 Flash如何以1/5价格挑战行业格局
  • 亚马逊小语种市场本地化广告秘籍,精准撬动海外订单
  • C++——堆 - 实践
  • 【超全】基于SSM的旅游宣传网站【包括源码+文档+调试】
  • 错过将遗憾半年!Open-AutoGLM最新Web功能更新全解读
  • 2025年企业稳健文化建设咨询公司推荐:诚信靠谱的企业文化服务机构有哪些? - 工业推荐榜
  • (Open-AutoGLM隐藏功能大曝光):90%用户不知道的GUI代理技巧
  • 视频推流平台EasyDSS无人机推流直播在安防监控中的智能应用
  • 学长亲荐10个AI论文工具,助继续教育学生轻松写论文!
  • 【超全】基于SSM的宠物领养管理系统【包括源码+文档+调试】
  • 2025年动车组高铁乘务培训学校排名榜,高铁乘务就业指导学校招生高中生推荐 - 工业品牌热点
  • 为什么顶级团队都在悄悄测试Open-AutoGLM做GUI自动化?真相曝光
  • 多模态融合方法详解,助力大模型学习之旅!
  • 2025最新!专科生毕业论文必备8个AI论文平台测评
  • 提示工程(Prompt Engineering)完全指南:让AI听话的终极秘诀!
  • 2025 GEO优化服务商精准甄选指南:全域布局下的价值锚点与决策路径 - 品牌推荐排行榜
  • MBA必看!10个降AIGC工具推荐,高效避坑指南
  • 2025年12月节能型陶瓷过滤机,陶瓷真空过滤机,盘式陶瓷过滤机厂家推荐:行业测评与选型指南 - 品牌鉴赏师
  • 2025布局葡萄牙:通过Safeguard Global名义雇主EOR降低用工风险 - 品牌2025
  • 大模型测试“地狱级“难度:为什么你的AI应用总给你“sorta“的答案?开发者必知的LARC解决方案来了!
  • 2025 GEO优化服务商甄选指南:从七大维度锚定精准增长伙伴 - 品牌推荐排行榜
  • 【专家级避坑指南】:Open-AutoGLM与Java生态兼容性问题全解析
  • 2025年12月上海除臭设备品牌推荐榜:分子筛除臭设备 废气处理/废气治理/环保/污水/除臭设备、废气除臭处理,深城环保凭国际领先技术登顶,守护洁净空气新生态 - 海棠依旧大
  • 网络安全 / 黑客从入门到精通指南【详细版】,零基础小白看这一篇就够
  • Open-AutoGLM点外卖核心技术曝光(AI自动化决策大揭秘)