【動態規劃】力扣221:最大正方形
在一個由 '0' 和 '1' 組成的二維矩陣內,找到只包含 '1' 的最大正方形,並返回其面積。
示例:
輸入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
輸出:4
方法1:暴力解法
由於正方形的面積等於邊長的平方,因此要找到最大正方形的面積,首先需要找到最大正方形的邊長,然後計算最大邊長的平方即可。
暴力法是最簡單直觀的做法,具體做法如下:
遍歷矩陣中的每個元素,每次遇到 1,則將該元素作為正方形的左上角;
確定正方形的左上角後,根據左上角所在的行和列計算可能的最大正方形的邊長(正方形的範圍不能超出矩陣的行數和列數),在該邊長範圍內尋找只包含 1 的最大正方形;
每次在下方新增一行以及在右方新增一列,判斷新增的行和列是否滿足所有元素都是 1。
方法2:動態規劃
可以使用動態規劃降低時間複雜度。
用 dp(i,j) 表示以 (i, j) 為右下角,且只包含 1 的正方形的邊長最大值。如果能計算出所有 dp(i,j) 的值,那麼其中的最大值即為矩陣中只包含 1 的正方形的邊長最大值,其平方即為最大正方形的面積。
那麼如何計算 dp 中的每個元素值呢?對於每個位置 (i, j),檢查在矩陣中該位置的值:
- 如果該位置的值是 0,則 dp(i,j)=0,因為當前位置不可能在由 1 組成的正方形中;
- 如果該位置的值是 1,則 dp(i,j) 的值由其 上方dp[i - 1][j]、左方dp[i][j - 1]和左上方dp[i - 1][j - 1] 三個相鄰位置的 dp 值決定。具體而言,當前位置的元素值等於三個相鄰位置的元素中的最小值加 1,狀態轉移方程為:dp(i,j) = min(dp(i−1,j),dp(i−1,j−1),dp(i,j−1))+1 。
此外,還需要考慮邊界條件。
根據左上角是否為‘1’來為dp矩陣賦值,所以i、j均從1開始。但是這樣就有個問題:當i=0或j=0就遺漏了matrix矩陣的右上角和坐下角,因此構建的dp矩陣是一個(m+1)*(n+1)型矩陣。
class Solution: def maximalSquare(self, matrix: List[List[str]]) -> int: m, n = len(matrix), len(matrix[0]) if m == 0 or n == 0: return 0 # 注意這裡構建的是(m+1)*(n+1)型矩陣 dp = [[0] * (n + 1) for _ in range(m + 1)] ans = 0 # for i in range(1, m + 1): for j in range(1, n + 1): if matrix[i - 1][j - 1] == '1': dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1 if dp[i][j] > ans: ans = dp[i][j] return ans * ans
時間複雜度:O(mn),其中 m 和 n 是矩陣的行數和列數。需要遍歷原始矩陣中的每個元素計算 dp 的值。
空間複雜度:O(mn),其中 m 和 n 是矩陣的行數和列數。建立了一個和原始矩陣大小相同的矩陣 dp。由於狀態轉移方程中的 dp(i, j) 由其上方、左方和左上方的三個相鄰位置的 dp 值決定,因此可以使用兩個一維陣列進行狀態轉移,空間複雜度優化至 O(n)。
也可以構建 m * n 的dp矩陣,matrix和dp 一一對應:如果 i 和 j 中至少有一個為 0,則以位置 (i, j) 為右下角的最大正方形的邊長只能是 1,因此 dp(i,j)=1 。
class Solution:
def maximalSquare(self, matrix: List[List[str]]) -> int:
if len(matrix) == 0 or len(matrix[0]) == 0:
return 0
maxSide = 0
rows, columns = len(matrix), len(matrix[0])
dp = [[0] * columns for _ in range(rows)]
for i in range(rows):
for j in range(columns):
if matrix[i][j] == '1':
if i == 0 or j == 0:
dp[i][j] = 1
else:
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
maxSide = max(maxSide, dp[i][j])
return maxSide * maxSide
作者:LeetCode-Solution
連結:https://leetcode-cn.com/problems/maximal-square/solution/zui-da-zheng-fang-xing-by-leetcode-solution/