1992. 找到所有的农场组

目录

题目解析 | 1992. 找到所有的农场组 —— 矩形农场识别问题

题目描述

输入输出示例

解题分析

解题思路与方法

1. 遍历矩阵

2. 寻找矩形右边界

3. 寻找矩形下边界

4. 标记矩形区域为已访问

5. 记录矩形坐标

代码实现(Python)

复杂度分析

方案比较

示例讲解

总结


题目解析 | 1992. 找到所有的农场组 —— 矩形农场识别问题

题目描述

给定一个大小为 m x n 的二维二进制矩阵 land,其中:

  • 0 表示一单位的森林土地,
  • 1 表示一单位的农场土地。

题目保证所有的农场土地都是以 矩形 形式组成的农场组,且不同的农场组之间不会在上下左右方向相邻(不会相互接触)。换句话说:

  • 每个农场组是一个完整的矩形区域,
  • 不同农场组之间至少有一圈 0 分隔。

你的任务是找到所有农场组的左上角和右下角坐标,返回一个二维数组,每个子数组是 [r1, c1, r2, c2],分别表示一个农场组的左上角和右下角坐标。

如果没有任何农场组,返回空数组。


输入输出示例

示例 1:

输入:
land = [
  [1,0,0],
  [0,1,1],
  [0,1,1]
]

输出:
[[0,0,0,0],[1,1,2,2]]

解释:
- 第一个农场组只有一个1,位于 (0,0) 位置。
- 第二个农场组是一个2x2矩形,左上角在 (1,1),右下角在 (2,2)。

示例 2:

输入:
land = [
  [1,1],
  [1,1]
]

输出:
[[0,0,1,1]]

解释:
只有一个农场组,整个矩阵都是农场土地。

示例 3:

输入:
land = [
  [0]
]

输出:
[]

解释:
没有任何农场组。

解题分析

题目重点在于:

  1. 农场组都是矩形
    这让我们可以用边界扫描确定一个农场组的位置,而不必考虑复杂的形状和连通性。
  2. 不同农场组之间不相邻
    这保证了每次遇到一个 1,它一定是一个新的农场组的左上角,避免重叠计数。
  3. 需要返回矩形的左上角和右下角坐标
    找到起点后,需要沿着矩形边界扩展宽度和高度。

解题思路与方法

1. 遍历矩阵

  • 对矩阵进行双重循环遍历,
  • 每遇到一个 1,即找到一个新农场组的左上角坐标 (r1, c1)

2. 寻找矩形右边界

  • 从左上角 (r1, c1) 向右扫描,确定矩形宽度(列范围 c1c2),
  • 直到遇到 0 或边界停止。

3. 寻找矩形下边界

  • 确定了宽度后,从左上角向下扫描行,
  • 逐行检查该列范围内是否全是 1
  • 如果整行对应列都是 1,继续向下扩展,
  • 否则停止,确定下边界行号 r2

4. 标记矩形区域为已访问

  • 将找到的矩形内所有 1 改为 0,防止后续重复计数。

5. 记录矩形坐标

  • [r1, c1, r2, c2] 记录到结果列表中。

代码实现(Python)

from typing import List

class Solution:
    def findFarmland(self, land: List[List[int]]) -> List[List[int]]:
        m, n = len(land), len(land[0])
        result = []
        
        for i in range(m):
            for j in range(n):
                if land[i][j] == 1:
                    r1, c1 = i, j
                    r2, c2 = i, j
                    
                    # 向右找宽度
                    while c2 + 1 < n and land[i][c2 + 1] == 1:
                        c2 += 1
                    
                    # 向下找高度
                    temp_r = i
                    while temp_r + 1 < m:
                        # 检查下一行的对应列是否全为1
                        all_one = True
                        for col in range(c1, c2 + 1):
                            if land[temp_r + 1][col] != 1:
                                all_one = False
                                break
                        if all_one:
                            temp_r += 1
                        else:
                            break
                    r2 = temp_r
                    
                    # 标记已访问区域
                    for x in range(r1, r2 + 1):
                        for y in range(c1, c2 + 1):
                            land[x][y] = 0
                    
                    result.append([r1, c1, r2, c2])
        
        return result

复杂度分析

  • 时间复杂度
    遍历矩阵 O(m*n),每个元素最多被访问两次(一次扫描,一次标记),整体是线性的。
  • 空间复杂度
    使用原地修改 land,空间复杂度为 O(1)

方案比较

  • DFS/BFS方法
    也可以用深度优先或广度优先遍历农场组,但由于题目保证农场为矩形,这样做较为繁琐且效率稍低。
  • 当前方法优点
    利用题目矩形性质直接按边界扫描,简单高效。

示例讲解

以示例1为例:

land = [
  [1,0,0],
  [0,1,1],
  [0,1,1]
]
  • 遍历到 land[0][0] == 1
    • 向右无延伸,宽度=1,
    • 向下无延伸,高度=1,
    • 标记 [0,0,0,0] 为已访问。
  • 继续遍历,到 land[1][1] == 1
    • 向右延伸到 land[1][2] == 1,宽度=2,
    • 向下延伸到 land[2][1], land[2][2] == 1,高度=2,
    • 标记区域 [1,1,2,2] 为已访问。
  • 结果为 [[0,0,0,0],[1,1,2,2]]

总结

  • 利用题目中“农场为矩形且不相邻”的特点,大大简化了问题,
  • 遍历时遇到1直接定位矩形边界,标记后避免重复,
  • 该方法简单易实现,时间空间效率都很好。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值