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

【LeetCode 每日一题】2257. 统计网格图中没有被保卫的格子数

Problem: 2257. 统计网格图中没有被保卫的格子数

文章目录

  • 整体思路
  • 完整代码
  • 时空复杂度
    • 时间复杂度:O(M*N + G*(M+N))
    • 空间复杂度:O(M*N)

整体思路

这段代码旨在解决一个二维网格问题:在一个 m x n 的房间里,给定守卫 guards 和墙壁 walls 的位置,计算出所有未被守卫监视不是障碍物(守卫或墙壁)的空格子数量。

守卫的监视范围是其所在行和列的四个方向(上、下、左、右),直到遇到边界、另一个守卫或一堵墙为止。

该算法采用了一种非常直观的 模拟 (Simulation)射线投射 (Ray Casting) 的方法。

  1. 第一步:初始化网格状态

    • 算法创建了一个与房间大小相同的 m x n 的二维数组 guarded。这个数组用来标记网格中每个格子的状态:
      • 0: 初始状态,表示一个空的、未被监视的格子。
      • -1: 表示一个障碍物(守卫或墙壁)。
      • 1: 表示一个被监视的格子。
    • 通过遍历 guardswalls 数组,将所有守卫和墙壁的位置在 guarded 数组中标记为 -1
  2. 第二步:模拟守卫的监视

    • 这是算法的核心。它遍历每一个 guard 的位置。
    • 对于每个守卫,它再遍历四个基本方向 DIRS(上、下、左、右)。
    • 对于每个方向,它模拟一条从守卫位置出发的“视线”:
      • int x = g[0] + dx; int y = g[1] + dy;: 初始化视线的起始点,即守卫旁边的第一个格子。
      • while (0 <= x && x < m && 0 <= y && y < n && guarded[x][y] != -1): 这个 while 循环是模拟视线延伸的关键。它会一直持续,直到:
        1. 视线超出了房间边界 (0 <= x && x < m && 0 <= y && y < n 不满足)。
        2. 视线遇到了一个障碍物 (guarded[x][y] != -1 不满足)。
      • guarded[x][y] = 1;: 在 while 循环内部,所有路径上的非障碍物格子都被标记为 1(被监视)。
      • x += dx; y += dy;: 将视线沿当前方向延伸一格。
  3. 第三步:统计未被监视的格子

    • 在所有守卫的监视范围都标记完毕后,guarded 数组就完整地反映了整个房间的状态。
    • 算法最后通过一个嵌套的 for 循环遍历整个 guarded 数组。
    • if (x == 0): 检查每个格子的状态。如果一个格子的状态仍然是 0,说明它既不是障碍物,也没有被任何守卫监视到。
    • ans++: 将计数器 ans 加一。
  4. 返回结果

    • 遍历结束后,ans 中就存储了所有未被监视的空格子数量。

完整代码

class Solution {// 定义四个方向的偏移量:上, 下, 左, 右private static final int[][] DIRS = { { 0, -1 }, { 0, 1 }, { -1, 0 }, { 1, 0 } };/*** 计算网格中未被守卫监视的空格子数量。* @param m       房间的行数* @param n       房间的列数* @param guards  守卫位置的数组* @param walls   墙壁位置的数组* @return 未被监视的空格子数量*/public int countUnguarded(int m, int n, int[][] guards, int[][] walls) {// 步骤 1: 初始化网格状态// 0: 空闲且未被监视, -1: 障碍物 (守卫或墙), 1: 被监视int[][] guarded = new int[m][n];// 将所有守卫的位置标记为障碍物for (int[] g : guards) {guarded[g[0]][g[1]] = -1;}// 将所有墙壁的位置标记为障碍物for (int[] w : walls) {guarded[w[0]][w[1]] = -1;}// 步骤 2: 模拟每个守卫的监视范围for (int[] g : guards) {// 对每个守卫,检查四个方向for (int[] d : DIRS) {int dx = d[0];int dy = d[1];// 从守卫旁边的格子开始int x = g[0] + dx;int y = g[1] + dy;// 沿着该方向一直延伸,直到遇到边界或障碍物while (0 <= x && x < m && 0 <= y && y < n && guarded[x][y] != -1) {// 将路径上的格子标记为“被监视”guarded[x][y] = 1;// 移动到下一个格子x += dx;y += dy;}}}// 步骤 3: 统计未被监视的格子int ans = 0;for (int[] row : guarded) {for (int x : row) {// 如果格子的状态仍然是 0,说明它未被监视if (x == 0) {ans++;}}}return ans;}
}

时空复杂度

  • M 是行数, N 是列数。
  • G 是守卫的数量 (guards.length)。
  • W 是墙壁的数量 (walls.length)。

时间复杂度:O(MN + G(M+N))

  1. 初始化 guarded 数组:创建一个 M x N 的数组,时间复杂度为 O(M*N)
  2. 标记障碍物
    • 遍历 guards 数组,G 次操作,时间为 O(G)。
    • 遍历 walls 数组,W 次操作,时间为 O(W)。
  3. 模拟监视
    • 外层循环遍历 G 个守卫。
    • 中间循环遍历 4 个方向。
    • 内层 while 循环,对于每个守卫的每个方向,最多延伸 M (垂直) 或 N (水平) 步。
    • 因此,处理一个守卫的时间复杂度是 O(M+N)
    • 处理所有守卫的总时间复杂度是 O(G * (M+N))
  4. 统计结果
    • 最后遍历 M x Nguarded 数组一次,时间复杂度为 O(M*N)

综合分析
总的时间复杂度是 O(M*N + G + W + G*(M+N) + M*N)。通常 GW 远小于 M*N。所以,复杂度可以简化为 O(MN + G(M+N))

空间复杂度:O(M*N)

  1. 主要存储开销:算法创建了一个名为 guarded 的二维整型数组。
  2. 空间大小:该数组的大小是 M x N
  3. 其他变量DIRS 是一个小的常量数组,其他变量如 dx, dy, x, y, ans 等都只占用常数空间。

综合分析
算法所需的额外空间主要由 guarded 状态数组决定。因此,其空间复杂度为 O(M*N)

参考灵神

http://www.dtcms.com/a/566521.html

相关文章:

  • 郑州西区做网站公司做网站的费用的会计分录
  • wordpress主题演示站点做旅游网站的数据怎么来
  • Linux iptables防火墙基础知识总结
  • 网站开发微信支付功能网站标题优化工具
  • 怎样做心理咨询网站学网络与新媒体后悔死了
  • 住房城乡建设行业从业人员wordpress 博客优化
  • 太原网站 制作个人网站备案没有座机
  • 温州网站外包网站界面一般用什么软件做
  • 上海 网站建设公司2022年今天新闻联播
  • Doris连接故障一键排查脚本
  • 青岛电商网站制作官方网站的网络营销功能分析
  • 教育网站制作实训报告如何搭建一个网站平台
  • 贵州城乡建设部网站首页什么是自媒体
  • SQLite Distinct 关键字
  • 祝贺公司网站上线做调查赚钱的网站有哪些
  • 网络直播网站开发注册网站好的平台
  • 黑龙江网站备案公司网站未备案
  • ThreadLocal用法及实现原理解析
  • 太原建筑市场网站中国建设银行邢台分行网站
  • 怎样利用关键词来打动读者
  • Deinterleaving of Mixtures of Renewal Processes
  • 设计师网站有哪些wordpress安装多说
  • 哪有网站给光头强做面企业官网小程序源码
  • 大同建设银行保安招聘网站淄博网站制作价格低
  • C#上位机卡顿解决方法1——获取内存占用率
  • 各大搜索引擎网站登录入口网站帮企业做推广价格怎么算
  • 哈尔滨网站建设优化网站页面构成要素
  • OCR图片识别翻译工具功能及源码
  • vue3 抽取el-drawer子组件
  • 杭州专业网站建设佛山cms模板建站