package com.freetymekiyan.algorithms.level.medium; /** * Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area. * <p> * For example, given the following matrix: * <p> * 1 0 1 0 0 * 1 0 1 1 1 * 1 1 1 1 1 * 1 0 0 1 0 * Return 4. * <p> * Company Tags: Apple, Airbnb, Facebook * Tags: Dynamic Programming * Similar Problems: (H) Maximal Rectangle */ public class MaximalSquare { /** * DP. * Finding the largest square's area is the same as finding the edge length. * The recurrence relation here is: * Suppose the largest edge length formed by current grid at matrix[i-1][j-1] is dp[i][j]. * If matrix[i - 1][j - 1] = 1, dp[i][j] = min(dp[i-1][j], dp[i][j], dp[i][j-1]) + 1. * If matrix[i - 1][j - 1] = 0, dp[i][j] = 0. * <p> * To understand the recurrence relation, draw a matrix. * Iff grid [i,j] is 1 and it's just a corners of other 1s, can the length expand. */ public int maximalSquare(char[][] matrix) { if (matrix == null) { return 0; } int r = matrix.length; int c = r == 0 ? 0 : matrix[0].length; int[][] dp = new int[r + 1][c + 1]; // First row and column are all 0. int maxLen = 0; for (int i = 1; i <= r; i++) { // Traverse dp array. Note the equal sign. for (int j = 1; j <= c; j++) { if (matrix[i - 1][j - 1] == '1') { // Update dp[i][j] and the max length. dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1; maxLen = Math.max(maxLen, dp[i][j]); } } } return maxLen * maxLen; // Return AREA here. } /** * DP. Space optimized. * Only the previous row and previous column are needed. * So reduce space usage to an array and an integer. */ public int maximalSquareB(char[][] matrix) { if (matrix == null) { return 0; } int r = matrix.length; int c = r == 0 ? 0 : matrix[0].length; int[] dp = new int[c + 1]; // Only need one row. int prev = 0; // Store dp[i-1][j-1]. int maxLen = 0; for (int i = 1; i <= r; i++) { for (int j = 1; j <= c; j++) { int temp = dp[j]; // Store dp[i-1][j-1] of next iteration. if (matrix[i - 1][j - 1] == '1') { dp[j] = Math.min(Math.min(dp[j - 1], dp[j]), prev) + 1; maxLen = Math.max(maxLen, dp[j]); } else { dp[j] = 0; // Have to update when grid is 0. } prev = temp; // dp[j] before update is the dp[i-1][j-1] for the next loop. } } return maxLen * maxLen; // Return the AREA here. } }