LeetCode 221. 最大正方形

個人LeetCode:https://leetcode-cn.com/u/ituring/

個人LeetCode刷題源碼[GitHub]:https://github.com/izhoujie/Algorithmcii

LeetCode 221. 最大正方形

題目

在一個由 0 和 1 組成的二維矩陣內,找到只包含 1 的最大正方形,並返回其面積。java

示例:git

輸入: 

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

輸出: 4

來源:力扣(LeetCode)
連接:https://leetcode-cn.com/problems/maximal-square
著做權歸領釦網絡全部。商業轉載請聯繫官方受權,非商業轉載請註明出處。github

解題思路

本題可用BFS/廣度優先搜索或者dp動態規劃解決;算法

思路1-BFS

思路解析:對於matrix[i][j]爲'1'的位置,若其matrix[i+1][j]、matrix[i][j+1]、matrix[i+1][j+1]也都爲'1',那麼由matrix[i][j]能夠獲得一個邊長爲2的正方形;
按照整個邏輯遞歸BFS便可嘗試擴大正方形的邊長;數組

  1. 遍歷找到'1'的位置,由此位置開始BFS,每成功擴展一次BFS邊長+1;
  2. 記錄全部位置爲'1'的BFS最大值即最大面積;

算法複雜度: m、n分別爲matrix的行和列網絡

  • 時間複雜度: $ {\color{Magenta}{\Omicron\left(mn * min(m,n)^{2}\right)}} $
  • 空間複雜度: $ {\color{Magenta}{\Omicron\left(mn\right)}} $

思路2-dp動態規劃

思路解析:與思路1類似,可是dp是把matrix[i][j]爲'1'位置的左邊、上邊和左上位置的數據亞索至[i][j]位置;
對於matrix[i][j]爲'1'的位置能獲得的最大正方形的邊長爲dp[i][j]:ui

\[{\color{Magenta}{dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1}} \]

步驟:code

  1. 對於0行和0列,只記錄是否有'1'便可;
  2. 從[1][1]位置開始dp,並每次記錄所獲得的最大邊長,dp完成後由獲得的最大邊長計算面積便可;

算法複雜度: m、n分別爲matrix的行和列遞歸

  • 時間複雜度: $ {\color{Magenta}{\Omicron\left(nm\right)}} $
  • 空間複雜度: $ {\color{Magenta}{\Omicron\left(1\right)}} $

算法源碼示例

package leetcode;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * @author ZhouJie
 * @date 2020年5月8日 下午5:06:45 
 * @Description: 221. 最大正方形
 *
 */
public class LeetCode_0221 {

}

class Solution_0221 {
	/**
	 * @author: ZhouJie
	 * @date: 2020年5月8日 下午6:49:30 
	 * @param: @param matrix
	 * @param: @return
	 * @return: int
	 * @Description: 1-BFS;
	 *
	 */
	public int maximalSquare_1(char[][] matrix) {
		if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
			return 0;
		}
		int row = matrix.length;
		int col = matrix[0].length;
		Deque<Integer> deque = new ArrayDeque<Integer>();
		int size = 0, maxS = 0;
		// 右方、下方、右下方的方位
		int[] dx = new int[] { 1, 0, 1 };
		int[] dy = new int[] { 0, 1, 1 };
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				// 若當前是1則開始BFS
				if (matrix[i][j] == '1') {
					deque.clear();
					// 保存座標,不使用數組,利用int整除和取模的特性存儲座標信息
					deque.offer(i * col + j);
					// 初始變長爲1
					int a = 1;
					boolean f = false;
					while (!deque.isEmpty()) {
						maxS = Math.max(a * a, maxS);
						size = deque.size();
						while (size-- > 0) {
							Integer p = deque.poll();
							int x = p / col;
							int y = p % col;
							int x0, y0;
							for (int k = 0; k < 3; k++) {
								x0 = x + dx[k];
								y0 = y + dy[k];
								// 當前位置的右方、下方、和右下方的位置也必須都是1才能擴大正方形的邊長,不然BFS到此爲止
								if (x0 < row && y0 < col && matrix[x0][y0] == '1') {
									deque.offer(x0 * col + y0);
								} else {
									f = true;
									break;
								}
							}
						}
						if (f) {
							break;
						}
						a++;
					}
				}
			}
		}
		return maxS;
	}

	/**
	 * @author: ZhouJie
	 * @date: 2020年5月8日 下午6:49:40 
	 * @param: @param matrix
	 * @param: @return
	 * @return: int
	 * @Description: 2-dp動態規劃;
	 *
	 */
	public int maximalSquare_2(char[][] matrix) {
		if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
			return 0;
		}
		int row = matrix.length;
		int col = matrix[0].length;
		// 記錄最大邊長
		char max = '0';
		// dp邏輯,第0行和第0列只須要記錄是否有1,從[1][1]開始dp,對於以後的[i][j]邏輯爲:
		// 若[i][j]不爲0,則:
		// dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1,dp[i][j]
		// dp[i][j]可能爲最大邊長,由於matrix自己就是dp所需的初始狀態,只是保存的爲char類型,須要轉int類型,因此能夠直接用matrix進行dp
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				if ((i == 0 || j == 0)) {
					if (max == '0' && matrix[i][j] == '1') {
						max = '1';
					}
				} else if (matrix[i][j] > '0') {
					matrix[i][j] = matrix[i][j - 1] < matrix[i - 1][j] ? matrix[i][j - 1] : matrix[i - 1][j];
					matrix[i][j] = matrix[i][j] < matrix[i - 1][j - 1] ? matrix[i][j] : matrix[i - 1][j - 1];
					matrix[i][j]++;
					max = max > matrix[i][j] ? max : matrix[i][j];
				}
			}
		}
		return (max - '0') * (max - '0');
	}
}
相關文章
相關標籤/搜索