题目
在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。
示例 1:
输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]] 输出:4 示例 2:
输入:matrix = [["0","1"],["1","0"]] 输出:1 示例 3:
输入:matrix = [["0"]] 输出:0 ?
提示:
m == matrix.length n == matrix[i].length 1 <= m, n <= 300 matrix[i][j] 为 '0' 或 '1'
来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/maximal-square 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
1.暴力求解? ? ? ??
????????我一开始没有想到动态规划,只想到了暴力求解:就是依次扫每一个格子,看是否满足以它为正方形的左上角构成的最大正方形。
# 暴力解法:从可能的最大情况下,一个一个的去扫整个矩形
class Solution:
def maximalSquare(self, matrix: List[List[str]]) -> int:
m, n = len(matrix), len(matrix[0]) # m行n列
max_len = min(m, n) # 正方形的最大边为m,n中较小的一个值
for cur_len in range(max_len, -1, -1): # 当前正方形的边长
i = 0
while i <= m - cur_len: # 垂直方向的移动
j = 0
next_i_len = cur_len
while j <= n - cur_len: # 水平方向的移动
next_j_len = 1
cur_square = matrix[i:i + cur_len] # 当前正方形
for row_index in range(cur_len):
row = cur_square[row_index]
cur_row = row[j:j + cur_len] # 当前正方形的每一行
flag = 0 # 用于判断要不要退出当前的外层循环(i层的)
for k in range(cur_len - 1, -1, -1):
if cur_row[k] == '0': # 从每一行的最后一个数开始判断,只要等于0,就不能构成当前最大的正方形
next_j_len = max(next_j_len, k + 1) # 计算下一步水平位移的增量,而不是每一次只增加1,这样节省了很多时间
flag = 1
break # 因为不能构成当前最大的正方形,所以直接跳出循环(j层的)
if flag:
next_i_len = min(next_i_len, row_index + 1) # 计算垂直方向的移动增量,而不是每一次只增1,这样子节省了很多时间
break # 因为正方形中有0出现,所以也跳出i层循环
else: # 如果当前的正方形都是由1组成的,则不会从上面的for循环由break跳出 那么当前的正方形就是面积最大的正方形,直接return即可
print(f'最长边:{cur_len}')
return cur_len ** 2
print(f'{next_i_len}*' * 100)
j += next_j_len # 水平方向的移动
i += next_i_len # 垂直方向的移动
2.动态规划
? ? ? ? 后来看了题解后,可以用动态规划求解,与上面不一样的是,这里选一个点作为正方形的最右下角的那个顶点,然后在这个点上记录能够组成的最大的正方形的边,而它的取值和它自身是否为0有关;同时和它左边,上边和左上角的点的值有关,具体的状态转移方程如下:
# 假设dp[i][j]表示的以(i,j)为右下角的最大正方的边长
# 则dp[i][j]的值由其左边,上边和左上角的值共同确定
则dp[i][j]的值的确定可能出现两种情况:
1.matrix[i][j]=0,则dp[i][j]直接等于0
2.matrix[i][j]!=0,则比较其左边,上边和左上角的值,dp[i][j]=min(dp[i-1][j],dp[i][j-1],d[i-1][j-1])+1
# 动态规划求解
class Solution:
def maximalSquare(self, matrix: List[List[str]]) -> int:
m, n = len(matrix), len(matrix[0])
dp = [[0 for j in range(n)] for i in range(m)] # 初始化一个dp数组
dp[0] = [int(i) for i in matrix[0]] # 更新dp第一行的值,和matrix中第一行的值相同
max_len = max(dp[0]) # 记录最长边
if m > 1:
for i in range(m):
dp[i][0] = int(matrix[i][0]) # 更新dp第一列的值,和matrix中第一列的值相同
dp[1][0] = int(matrix[1][0])
max_len = max(max_len, dp[1][0])
for i in range(1, m):
for j in range(1, n):
if matrix[i][j] == '0':
dp[i][j] = 0
else:
dp[i][j] = min(int(dp[i - 1][j]), int(dp[i][j - 1]), int(dp[i - 1][j - 1])) + 1
max_len = max(max_len, dp[i][j])
return max_len ** 2
通过截图
?同步更新于个人博客系统:LeetCode之最大正方形(暴力求解和动态规划求解)
|