题目
有 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。
示例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 <= rooms[i].length <= 1000
3. 所有房间中的钥匙数量总计不超过 3000。
思路
这一题看起来文字很多,但其实不是特别难,这题的核心就在于
从0号房间出发,遍历0号房间的钥匙列表,然后用相应的钥匙去开相应的房间,然后再遍历开的相应房间的钥匙列表,再去开门
核心就在于进房间,拿钥匙,再进房间,再拿钥匙,这里有人可能就会有疑问了,那代码什么时候终止呢?
问的好,我们只需要定义一个大小为N的数组用来表示,每间房间的访问情况,如果已经访问过则为1,没有访问过则为初始值0,这样我们从0号房间出发,一直到最后再没有新的房间能打开结束
废话少说,下面进入代码
代码
首先在主函数中我们做的就是获取房间数量然后初始化记录数组,用于记录房间的访问情况,初始时初始化为0
然后进入dfs函数,传入0作为第一次访问的房间号
class Solution {
public:
bool canVisitAllRooms(vector<vector<int>>& rooms) {
int m = rooms.size();
vector<int> record(m , 0);
dfs(rooms, 0, record);
}
};
然后进入dfs函数中,首先我们把当前访问的房间的记录数组的值改为1,表示已经访问过
void dfs(vector<vector<int>>& array, int u, vector<int>& record, int n) {
record[u] = 1;
}
然后我们遍历这个房间的钥匙列表,依靠每一个钥匙去访问相应的房间,这里要注意一个细节
因为钥匙是可以重复的,比如0号房间里可能有1号房间的钥匙,2号房间里也可能有1号房间的钥匙,所以这里要做一个剪枝,如果钥匙对应的房间已经访问过了,那么就跳过这把钥匙,避免重复计算
然后要注意dfs函数u这个参数表示的是钥匙对应的相应房间号,所以我们要把钥匙值传入
void dfs(vector<vector<int>>& array, int u, vector<int>& record, int n) {
record[u] = 1;
for(auto number : array[u]) {
if(!record[number]){
dfs(array, number, record, n);
}
}
}
dfs函数结束后我们遍历一遍记录数组,如果还有值为0就代表还有房间没进入,则直接返回false,循环外直接返回true
最后是完整代码:
class Solution {
public:
void dfs(vector<vector<int>>& array, int u, vector<int>& record, int n) {
record[u] = 1;
for(auto number : array[u]) {
if(!record[number]){
dfs(array, number, record, n);
}
}
}
bool canVisitAllRooms(vector<vector<int>>& rooms) {
int m = rooms.size();
vector<int> record(m , 0);
dfs(rooms, 0, record, m);
for(int i = 0; i < m; i++) {
if(!record[i]) {
return false;
}
}
return true;
}
};