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

每日两道leetcode

841. 钥匙和房间 - 力扣(LeetCode)

题目

有 n 个房间,房间按从 0 到 n - 1 编号。最初,除 0 号房间外的其余所有房间都被锁住。你的目标是进入所有的房间。然而,你不能在没有获得钥匙的时候进入锁住的房间。

当你进入一个房间,你可能会在里面找到一套 不同的钥匙,每把钥匙上都有对应的房间号,即表示钥匙可以打开的房间。你可以拿上所有钥匙去解锁其他房间。

给你一个数组 rooms 其中 rooms[i] 是你进入 i 号房间可以获得的钥匙集合。如果能进入 所有 房间返回 true,否则返回 false

    示例 1:

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

    示例 2:

    输入:rooms = [[1,3],[3,0,1],[2],[0]]
    输出:false
    解释:我们不能进入 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] 的值 互不相同

    思路

    1. 定义一个队列存储钥匙,每访问一个房间就将该房间的钥匙入队,每次拿出队首的一把钥匙,要是对应的房间已经被访问,则继续取,直到钥匙被取完。此时若是所有房间都被访问了,那么就返回true,否则返回false。

    代码实现

    class Solution {
    public:bool canVisitAllRooms(vector<vector<int>>& rooms) {int cnt = rooms.size()-1, key;queue<int> keys;if(!rooms[0].empty()) for(int i = 0; i < rooms[0].size(); i++) keys.push(rooms[0][i]);if(rooms[0].empty()) rooms[0].push_back(-1);else rooms[0][0] = -1;while(!keys.empty()) {key = keys.front();cout << key << endl;keys.pop();if(rooms[key].empty() || rooms[key][0] != -1) cnt--;else continue;if(!rooms[key].empty()) for(int i = 0; i < rooms[key].size(); i++) keys.push(rooms[key][i]);if(rooms[key].empty()) rooms[key].push_back(-1);else rooms[key][0] = -1;}if(cnt != 0) return false;return true;}
    };

    复杂度分析

    • 时间复杂度:O(n+keys)。
    • 空间复杂度:最坏空间复杂度O(keys)。

    知识积累

    • 关于for循环的auto的使用:
      • for(auto i : vector)其中auto会拷贝容器内的vector,修改时不会改变原容器当中的值,只会改变拷贝的vector。
      • for(auto& i : vector),i就变成vector的引用,不发生拷贝,一定程度上会减少操作数,但是对i进行修改会修改到原vector。 
    • vector.resize(size,[value])动态指定vector空间的大小,若指定大小小于原大小则删除多余元素,若大于,则会使用value填充,若不指定value则会默认初始化。
    • queue.emplace(x),也是push的一种逻辑,但是push需要先创建对象的副本,再将其移动到容器中,涉及额外的复制及移动操作;而emplace直接在容器中构造对象,没有额外的复制和移动操作。

    官方题解

    1. 深度优先搜索
      1. 官方题解额外定义了一个访问数组,在获取钥匙前先判断是否访问过对应房间而决定是否需要取这个钥匙,一进一出就比我的钥匙入队方法要快了不少了,而且所用的空间最大也就是O(n),因为递归的深度最深就是房间数,钥匙是平行的空间深度。
      2. 时间复杂度是O(n+keys),空间复杂度是O(n)。
      3. 以下是我看完题解后自己仿写的实现:
        class Solution {
        public:vector<int> vis;int num;void dfs(vector<vector<int> >& rooms, int key) {vis[key] = true;num++;for(auto &i : rooms[key]) {if(!vis[i]) dfs(rooms, i);}}bool canVisitAllRooms(vector<vector<int>>& rooms) {int n = rooms.size();num = 0;vis.resize(n);dfs(rooms, 0);if(num == n) return true;return false;}
        };

    2. 广度优先搜索
      1. 广度优先搜索的方法类似我的实现,官方代码增加数组做判断避免重复操作,另外queue的push操作也以更高效的emplace操作代替。
    http://www.xdnf.cn/news/284.html

    相关文章:

  1. 4.17-4.18学习总结 多线程
  2. STP协议中的四种端口状态
  3. 熵权法+TOPSIS+灰色关联度综合算法(Matlab实现)
  4. 在 Babylon.js 中实现智能异步资源加载队列管理
  5. 力扣DAY56-59 | 热100 | 回溯:子集、电话号码的字母组合、组合总和、括号生成
  6. 【裁判文书网DES3数据解密】逆向分析
  7. windwos脚本 | 基于scrcpy,只投声音、只投画面
  8. MySQL中高级语法
  9. 博客标题栏添加一个 About Me
  10. RUI桌面TV版最新版免费下载-安卓电视版使用教程
  11. 二叉树理论基础
  12. static关键字
  13. qt QGroupButton 实现两个QPushButton的互斥
  14. 动态计算FPS(每秒帧数)的方法
  15. Jsp技术入门指南【六】jsp脚本原理及隐式对象
  16. 关于AI提示工程的详解,分点说明其核心概念、关键技巧和应用场景
  17. 语音合成之二TTS模型损失函数进化史
  18. 极狐GitLab 项目和群组的导入导出速率限制如何设置?
  19. Linux 文件查找终极指南:find, locate, grep 等命令详解
  20. 18-算法打卡-哈希表-两数之和-leetcode(1)-第十八天
  21. 智能体时代的产业范式确立,中国企业以探索者姿态走出自己的路
  22. [密码学实战]详解gmssl库与第三方工具兼容性问题及解决方案
  23. Python语言基础教程(上)4.0
  24. 15.4K Star!Vercel官方出品,零基础构建企业级AI聊天机器人
  25. 进程(转账,卖票)
  26. C#核心笔记——(六)框架基础
  27. 【MySQL】数据库和表的操作详解
  28. 6.6 “3步调用ChatGPT打造高可靠Python调度器,零依赖实现定时任务自动化“
  29. Linux工具学习之【vim】
  30. 医学图像中的不同模态图像详细介绍