LeetCode 841:钥匙和房间 Keys and Rooms

  • 2019 年 10 月 7 日
  • 筆記

题目:

N 个房间,开始时你位于 0 号房间。每个房间有不同的号码:0,1,2,...,N-1,并且房间里可能有一些钥匙能使你进入下一个房间。

在形式上,对于每个房间 i 都有一个钥匙列表 rooms[i],每个钥匙 rooms[i][j][0,1,...,N-1] 中的一个整数表示,其中 N = rooms.length。钥匙 rooms[i][j] = v 可以打开编号为 v 的房间。

最初,除 0 号房间外的其余所有房间都被锁住。

你可以自由地在房间之间来回走动。

如果能进入每个房间返回 true,否则返回 false

There are N rooms and you start in room 0. Each room has a distinct number in 0, 1, 2, ..., N-1, and each room may have some keys to access the next room.

Formally, each room i has a list of keys rooms[i], and each key rooms[i][j] is an integer in [0, 1, ..., N-1] where N = rooms.length. A key rooms[i][j] = v opens the room with number v.

Initially, all the rooms start locked (except for room 0).

You can walk back and forth between rooms freely.

Return true if and only if you can enter every room.

示例 1:

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

示例 2:

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

提示:

  1. 1 <= rooms.length <= 1000
  2. 0 &lt;= rooms[i].length &lt;= 1000
  3. 所有房间中的钥匙数量总计不超过 3000

Note:

  1. 1 <= rooms.length <= 1000
  2. 0 <= rooms[i].length <= 1000
  3. The number of keys in all rooms combined is at most 3000.

解题思路:

很简单的一道题,从0号房间开始递归遍历就可以了。唯一需要注意的是如何判断房间是否访问过。可以用set哈希表把已访问过的房间号记录下来,最后如果哈希表长度和rooms长度相等,那么就意味着所有房间均可到达。

代码:

Set集合(Java):

class Solution {      Set<Integer> set = new LinkedHashSet<>();        public boolean canVisitAllRooms(List<List<Integer>> rooms) {          helper(rooms, 0);          return set.size() == rooms.size();//长度相等则可以到达所有房间      }        private void helper(List<List<Integer>> rooms, int index) {          if (set.contains(index)) return;           set.add(index);//已访问房间号加入哈希表          for (Integer i : rooms.get(index)) {//遍历房间的每一个钥匙                  helper(rooms, i);//进入递归          }      }  }  

可以看到用哈希表解题方法在递归期间会多出许多set函数的调用,如 set.add() 、set.contains(),相对很多这道题解题时间,这个开销是很大。对这道题而言,是完全可以用数组避免的。

Java:

class Solution {        public boolean canVisitAllRooms(List<List<Integer>> rooms) {          int len = rooms.size();          int[] visited = new int[len];//初始化等长数组,数组每个值默认为0          helper(rooms, 0, visited);          for (int i : visited)              if (i == 0) return false;//数组中依然有0,则证明有房间未访问到          return true;      }        private void helper(List<List<Integer>> rooms, int index, int[] visited) {          if (visited[index] == 1) return;//如果该房间已访问过,直接返回          visited[index] = 1;//在访问    的房间,改为1来标记          for (Integer i : rooms.get(index)) {//遍历              helper(rooms, i, visited);          }      }  }  

Python:

class Solution:      def canVisitAllRooms(self, rooms: List[List[int]]) -> bool:          size=len(rooms)          self.visited = [False]*size # 初始化等长数组,默认为False,所有房间均未访问          self.helper(rooms, 0)          return all(self.visited)        def helper(self, rooms: List[List[int]], index: int) -> None:          if self.visited[index]:#如果为True,该房间已访问过,直接返回              return          self.visited[index] = True #在访问的房间标记为True          for i in rooms[index]:#遍历钥匙              self.helper(rooms, i)#进入递归函数