算法-最大单入口空闲区域

题目描述

给定一个 m x n 的矩阵,由若干字符 'X' 和 'O'构成,'X'表示该处已被占据,'O'表示该处空闲,请找到最大的单入口空闲区域。

解释:

空闲区域是由连通的'O'组成的区域,位于边界的'O'可以构成入口,

单入口空闲区域即有且只有一个位于边界的'O'作为入口的由连通的'O'组成的区域。

如果两个元素在水平或垂直方向相邻,则称它们是"连通"的。

输入描述

第一行输入为两个数字,第一个数字为行数m,第二个数字为列数n,两个数字以空格分隔,1<=m,n<=200。

剩余各行为矩阵各行元素,元素为'X'或'O',各元素间以空格分隔。

输出描述

若有唯一符合要求的最大单入口空闲区域,输出三个数字

  • 第一个数字为入口行坐标(0~m-1)
  • 第二个数字为入口列坐标(0~n-1)
  • 第三个数字为区域大小

三个数字以空格分隔;

若有多个符合要求,则输出区域大小最大的,若多个符合要求的单入口区域的区域大小相同,则此时只需要输出区域大小,不需要输出入口坐标。

若没有,输出NULL。

示例1

输入

复制代码
4 4
X X X X
X O O X
X O O X
X O X X

输出

复制代码
3 1 5

说明

存在最大单入口区域,入口坐标(3,1),区域大小5

示例2

输入

复制代码
4 5
X X X X X
O O O O X
X O O O X
X O X X O

输出

复制代码
3 4 1

说明

存在最大单入口区域,入口坐标(3,4),区域大小1

示例3

输入

复制代码
5 4
X X X X
X O O O
X O O O
X O O X
X X X X

输出

复制代码
NULL

示例4

输入

复制代码
5 4
X X X X
X O O O
X X X X
X O O O
X X X X

输出

复制代码
3

说明

存在两个大小为3的最大单入口区域,两个入口坐标分别为(1,3)、(3,3)

解题思路

  1. 问题理解我们需要在给定的矩阵中找出所有由连通的 'O' 组成的区域,其中恰好只有一个边界上的 'O'(即入口)。然后在这些区域中,找到最大的一个。如果有多个区域大小相同且并列最大,则只输出该大小;如果只有一个最大,则输出入口坐标和大小;如果没有符合条件的区域,输出 "NULL"。
  2. 核心步骤
  • 遍历矩阵每个格子,遇到未访问的 'O' 时,进行广度优先搜索(BFS)或深度优先搜索(DFS)找出整个连通区域。
  • 在遍历过程中,统计该区域中位于边界的格子数量,并记录其中一个边界格子的坐标(如果有)。
  • 如果边界格子数量恰好为 1,则该区域为单入口区域,记录其大小和入口坐标。
  • 比较所有单入口区域的大小,找出最大值,并记录最大值出现的次数以及第一次出现时的入口坐标(用于唯一情况)。
  • 最后根据统计结果输出。
  1. 注意事项
  • 边界条件:行坐标为 0 或 m-1,列坐标为 0 或 n-1。
  • 使用 visited 数组避免重复访问。
  • 输入格式:第一行 m 和 n,接下来 m 行每行 n 个字符,以空格分隔。
  • 输出格式:严格按题目要求,数字间用空格分隔,无多余空格。

JAVA实现

java 复制代码
public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int m = sc.nextInt();
    int n = sc.nextInt();
    char[][] grid = new char[m][n];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            grid[i][j] = sc.next().charAt(0);
        }
    }
    sc.close();

    boolean[][] visited = new boolean[m][n];
    int maxSize = 0;          // 当前找到的最大单入口区域大小
    int countMax = 0;          // 最大区域出现的次数(用于判断是否唯一)
    int entryR = -1, entryC = -1; // 当最大区域唯一时,记录其入口坐标
    // 方向数组:上下左右
    int[][] DIRS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            // 遇到未访问的 'O',开始 BFS
            if (grid[i][j] == 'O' && !visited[i][j]) {
                // BFS 队列
                Queue<int[]> queue = new LinkedList<>();
                queue.offer(new int[]{i, j});
                visited[i][j] = true;

                int size = 0;               // 当前区域大小
                int borderCount = 0;         // 该区域中位于边界的格子数
                int firstBorderR = -1, firstBorderC = -1; // 第一个遇到的边界格子坐标

                while (!queue.isEmpty()) {
                    int[] cur = queue.poll();
                    int r = cur[0];
                    int c = cur[1];
                    size++;

                    // 判断是否在边界上
                    if (r == 0 || r == m - 1 || c == 0 || c == n - 1) {
                            borderCount++;
                            if (borderCount == 1) { // 记录第一个边界格子作为入口候选
                                firstBorderR = r;
                                firstBorderC = c;
                            }
                    }

                    // 探索四个方向
                    for (int[] d : DIRS) {
                        int nr = r + d[0];
                        int nc = c + d[1];
                        if (nr >= 0 && nr < m && nc >= 0 && nc < n
                                && grid[nr][nc] == 'O' && !visited[nr][nc]) {
                            visited[nr][nc] = true;
                            queue.offer(new int[]{nr, nc});
                        }
                    }
                }

                // 如果该区域恰好只有一个边界格子,则是单入口区域
                if (borderCount == 1) {
                    if (size > maxSize) {
                        maxSize = size;
                        countMax = 1;
                        entryR = firstBorderR;
                        entryC = firstBorderC;
                    } else if (size == maxSize) {
                        countMax++;
                    }
                }
            }
        }
    }

    // 输出结果
    if (maxSize == 0) {
        System.out.println("NULL");
    } else if (countMax > 1) {
        // 多个最大区域且大小相同,只输出大小
        System.out.println(maxSize);
    } else {
        // 唯一最大区域,输出入口坐标和大小
        System.out.println(entryR + " " + entryC + " " + maxSize);
    }
}
相关推荐
千寻girling2 小时前
机器学习 | 逻辑回归 | 尚硅谷学习
java·人工智能·python·学习·算法·机器学习·逻辑回归
Shadow(⊙o⊙)2 小时前
C++常见错误解析2.0
开发语言·数据结构·c++·后端·学习·算法
永远不会的CC2 小时前
研0上岸找实习面试经历
python·算法·面试
帅小伙―苏2 小时前
力扣483找到字符串中所有字母异位词
算法·leetcode
小O的算法实验室2 小时前
2022年IEEE TETCI,基于矩阵的进化计算,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
欧米欧2 小时前
STRING的底层实现
前端·c++·算法
smj2302_796826522 小时前
解决leetcode第3906题统计网格路径中好整数的数目
python·算法·leetcode
KobeSacre2 小时前
leetcode 树
算法·leetcode·职场和发展
6Hzlia2 小时前
【Hot 100 刷题计划】 LeetCode 104. 二叉树的最大深度 | C++ 自底向上递归最优解
算法