在问 · 算法题解

841. 钥匙和房间

题目描述

有 n 个房间,编号 0 到 n - 1。只有 0 号房间没上锁,其余房间都要用钥匙才能进入。

输入数组 rooms,rooms[i] 是 i 号房间里放着的钥匙,每把钥匙上写着它能打开的房间号。进入一个房间后可以拿走其中所有钥匙,钥匙可以反复使用。

从 0 号房间出发。如果最终能进入每一个房间,返回 true,否则返回 false。

示例 1
输入:rooms = [[1],[2],[3],[]]
输出:true

解释:依次用钥匙 1、2、3 打开后面的房间,全部可以进入。

示例 2
输入:rooms = [[1,3],[3,0,1],[2],[0]]
输出:false

解释:没有任何房间里有钥匙 2,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] 中的值互不相同。

解题思路

把房间看作节点,房间 i 里有钥匙 k 就连一条 i → k 的有向边。问题变成:从节点 0 出发能否到达所有节点。用栈做 DFS:取出一个房间,遍历其中的钥匙,没开过的房间就标记为已访问并压栈。最后比较已访问数量和房间总数。

为什么正确

visited 中的房间都能从 0 号房间到达;栈里的房间是已经打开、但钥匙还没拿出来的房间。

复杂度分析

时间 O(n + 钥匙总数),每个房间只进栈一次,每把钥匙只看一次。空间 O(n)。

易错点

要在压栈时就标记已访问,否则同一把钥匙出现在多个房间时,同一房间会被重复压栈。钥匙可能指向自己或已开过的房间,必须跳过。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def canVisitAllRooms(self, rooms: List[List[int]]) -> bool:
        visited = {0}
        stack = [0]
        while stack:
            room = stack.pop()
            for key in rooms[room]:
                if key not in visited:
                    visited.add(key)
                    stack.append(key)
        return len(visited) == len(rooms)

载入编辑器,自己跑一遍 →

图论 专题的其他题目

查看 图论 全部题目 →