最大正方形 Python题解

最大正方形

题目描述

在一个 n × m n\times m n×m 的只包含 0 0 0 和 1 1 1 的矩阵里找出一个不包含 0 0 0 的最大正方形,输出边长。

输入格式

输入文件第一行为两个整数 n , m ( 1 ≤ n , m ≤ 100 ) n,m(1\leq n,m\leq 100) n,m(1≤n,m≤100),接下来 n n n 行,每行 m m m 个数字,用空格隔开, 0 0 0 或 1 1 1。

输出格式

一个整数,最大正方形的边长。

样例 #1

样例输入 #1

复制代码
4 4
0 1 1 1
1 1 1 0
0 1 1 0
1 1 0 1

样例输出 #1

复制代码
2

题解

这道题AcWing、洛谷和leetCode都有,只是输入还有输出的些微区别,这里只提供洛谷的Python代码,思路是一样的。

这道题其实不难看出来可以用动态规划做,但是我做这道题的时候是有人要求我先用前缀和做一遍了,所以我这里提供两种思路

1、前缀和

这道题前缀和做法其实很简单,就是看我们想要通过求的正方形的前缀和来求该正方形的面积,如果求出来的面积与正方形边长平方相等,那么这个边长的正方形就满足要求

复制代码
if 通过前缀和求的面积 == 正方形边长 ** 2:
	return True

怎么通过前缀和求矩形面积呢?我们可以通过下面公式来计算:

设 i 2 , j 2 i_2, j_2 i2,j2 为矩形右下角, i 1 , j 1 = i 2 − l e n S q u a r e + 1 , j 2 − l e n S q u a r e + 1 i_1, j_1 = i_2 - lenSquare + 1, j_2 - lenSquare + 1 i1,j1=i2−lenSquare+1,j2−lenSquare+1 为矩形左上角,那么通过前缀和求矩形面积公式为:
S i z e ( S q u a r e ) = P r e f i x i 2 j 2 − P r e f i x i 1 − 1 j 2 − P r e f i x i 2 j 1 − 1 + P r e f i x i 1 − 1 j 1 − 1 Size(Square) =Prefixi_2j_2 -Prefixi_1-1j_2-Prefixi_2j_1-1 +Prefixi_1-1j_1-1 Size(Square)=Prefixi2j2−Prefixi1−1j2−Prefixi2j1−1+Prefixi1−1j1−1

下面这张图为上图的前缀和矩阵:

那么穷举求出每种正方形边长的情况,我们就可以得到可能的正方形边长

欸,别急,直接穷举正方形边长还是慢了,正方形边长是从小到大穷举的,我们可以使用二分来加速对边长的举证:

复制代码
if mid正方边长满足要求:
	我们去找是否存在更大的边长满足要求:left = mid + 1
else:
	mid长度都不符合要求的,直接去找更小的边长了: right = mid - 1

最后得出Python代码(时间复杂度为 O ( N 2 l o g 2 N ) O(N^2log_2N) O(N2log2N)):

python 复制代码
def judge(lenEdge, Prefix):
    global N, M
    for i in range(lenEdge, N+1):
        for j in range(lenEdge, M+1):
            if Prefix[i][j] - Prefix[i-lenEdge][j] - Prefix[i][j-lenEdge] + Prefix[i-lenEdge][j-lenEdge] == lenEdge**2:
                return True
    else:
        return False


N, M = map(int, input().strip().split())
A = [[0 for _ in range(M+1)]]
for i in range(1, N+1):
    tmp = [0]
    tmp.extend(map(int, input().strip().split()))
    A.append(tmp)
Prefix = [[0 for _ in range(M+1)] for _ in range(N+1)]
for i in range(1, N+1):
    for j in range(1, M+1):
        Prefix[i][j] = Prefix[i-1][j] + Prefix[i][j-1] - Prefix[i-1][j-1] + A[i][j]
left, right = 0, min(N, M)
ans = 0
while left <= right:
    mid = (left + right) // 2
    if judge(mid, Prefix):
        ans = max(ans, mid)
        left = mid + 1
    else:
        right = mid - 1
print(ans)

2、动态规划法

动态规划法的想法更容易想到,这里用图来说明一下:

定义 i , j i,j i,j为正方形的左下角坐标,且 d p i j dpij dpij存的是该正方形的边长
( 4 , 4 ) (4,4) (4,4)代表的正方形的边长可以从红色、蓝色、绿色,( ( 3 , 3 ) , ( 3 , 4 ) , ( 4 , 3 ) (3,3),(3,4),(4,3) (3,3),(3,4),(4,3))三种颜色的正方形来得出,

可以看出来,黑色框出正方形边长为1+1 = 2,通过多画图推导,得出下面的公式:
d p i j = m i n ( d p i − 1 j , d p i j − 1 , d p i − 1 j − 1 ) + 1 dpij = min(dpi-1j,dpij-1,dpi-1j-1) + 1 dpij=min(dpi−1j,dpij−1,dpi−1j−1)+1

时间复杂度为 O ( N 2 ) O(N^2) O(N2)

python 复制代码
N, M = map(int, input().strip().split())
A = [[0 for _ in range(M)]] + [[0] + list(map(int, input().strip().split())) for _ in range(N)]
dp = [[0 for _ in range(M+1)] for _ in range(N+1)]
ans = 0
for i in range(1, N+1):
    for j in range(1, M+1):
        if A[i][j] == 1:
            dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
            ans = max(ans, dp[i][j])
print(ans)
相关推荐
优橙教育2 小时前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
想会飞的蒲公英3 小时前
计算机怎样读取中文文本:编码、清洗与标准化
人工智能·python·自然语言处理
SeaTunnel4 小时前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
深度研习笔记4 小时前
OpenCV工业视觉实战09|项目EXE打包+工控机无环境部署+后台常驻运行,彻底脱离Python环境,完成项目最终交付
python·opencv·webpack
碎光拾影4 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
CCPC不拿奖不改名4 小时前
大模型推理架构与开源生态知识整理
数据库·windows·python·架构·langchain·开源·github
Marst Code5 小时前
(python)2026Plotly 库评估:交互式可视化到底值不值得引入?
开发语言·python
databook5 小时前
当散点图不够用时:用 t-SNE 可视化多维数据
python·数据分析·数据可视化
Miao121315 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
CRMEB系统商城6 小时前
开源自建还是SaaS订阅?算一笔3年经济账
java·大数据·开发语言·开源