There are n rooms labeled from 0 to n - 1 and all the rooms are locked except for room 0. Your goal is to visit all the rooms. However, you cannot enter a locked room without having its key.
When you visit a room, you may find a set of distinct keys in it. Each key has a number on it, denoting which room it unlocks, and you can take all of them with you to unlock the other rooms.
Given an array rooms where rooms[i] is the set of keys that you can obtain if you visited room i, return true if you can visit all the rooms, or false otherwise.
Example 1:
Input: rooms = [[1],[2],[3],[]]
Output: true
Explanation:
We visit room 0 and pick up key 1.
We then visit room 1 and pick up key 2.
We then visit room 2 and pick up key 3.
We then visit room 3.
Since we were able to visit every room, we return true.
Example 2:
Input: rooms = [[1,3],[3,0,1],[2],[0]]
Output: false
Explanation: We can not enter room number 2 since the only key that unlocks it is in that room.
Constraints:
题目明显可以采用递归的思路。获取当前第k个房间的钥匙,通过递归,依次进入第k个房间所能拿到的钥匙对应的房间… …若当前房间已经能被访问,则退出递归。通过 boolean flag[]标记哪些房子可以被访问。
class Solution {
public boolean canVisitAllRooms(List<List<Integer>> rooms) {
if(rooms.size() == 0) {
return true;
}
int n = rooms.size(); //房间的数量
boolean flag[] = new boolean[n]; //标志哪个房间可以被访问
visitRoom(rooms, flag, 0);
for(int r = 1; r < n; r++) {
if(!flag[r]) {
return false;
}
}
return true;
}
public void visitRoom(List<List<Integer>> rooms, boolean flag[], int k) {
if(flag[k]) {
return;
}
flag[k] = true;
List<Integer> getKey = rooms.get(k);
for(int i = 0; i < getKey.size(); i++) {
visitRoom(rooms, flag, getKey.get(i));
}
}
}
上述递归的方法,其实也就是我们常说的DFS深度优先搜索。
而递归其实就是隐式栈,所以我们也可以用显式栈来实现。栈的先进后出其实是实现回退上一步的方式。不管是显示栈调用还是隐式的方法递归都可以。
LeetCode上给出的Depth-First Search的Solution,其实就是用到了栈Stack。当访问当前房间时,将能够获取到的房间钥匙入栈,并表示这些对应的房间均可被访问。随后依次出栈继续搜索,直到栈为空,所有可被访问的房间均已被访问。
class Solution {
public boolean canVisitAllRooms(List<List<Integer>> rooms) {
int n = rooms.size(); //房间的数量
boolean flag[] = new boolean[n]; //标志哪个房间可以被访问
flag[0] = true;
Stack<Integer> stack = new Stack(); //用于记录当前可进入的房间号,依次入栈并出栈,实现递归
stack.push(0);
while(!stack.isEmpty()) {
List<Integer> keyList = rooms.get(stack.pop());
for(int key: keyList) {
if(!flag[key]) {
flag[key] = true;
stack.push(key);
}
}
}
for(int r = 1; r < n; r++) {
if(!flag[r]) {
return false;
}
}
return true;
}
}
上述两种方法均采用了DFS,也可以采用BFS,借助队列实现:
class Solution {
public boolean canVisitAllRooms(List<List<Integer>> rooms) {
int n = rooms.size(); //房间的数量
boolean flag[] = new boolean[n]; //标志哪个房间可以被访问
flag[0] = true;
Queue<Integer> queue = new LinkedList<Integer>();
queue.offer(0);
while(!queue.isEmpty()) {
List<Integer> keyList = rooms.get(queue.poll());
for(int key: keyList) {
if(!flag[key]) {
flag[key] = true;
queue.offer(key);
}
}
}
for(int r = 1; r < n; r++) {
if(!flag[r]) {
return false;
}
}
return true;
}
}
DFS:(Depth First Search)深度优先搜索
我们常用的递归,回溯都属于DFS。
可以通俗的理解为,一层一层往下走,当遇到一条路走不通的情况下,就返回上一层换条路接着走。
其中要注意的是算法初始化、搜索规则、结束条件。一般用堆或栈来辅助实现DFS算法。
代码实现思路:(非递归)
BFS:(Breath First Search)广度优先搜索
BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。一般用队列来辅助实现BFS算法。
代码实现思路: