题目:221. 最大正方形
类别:动态规划
在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。
示例:
输入:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
输出: 4
解题思路:
运用动态规划思想进行解题,创建二维数组或一维数组来保存数据的状态,即使用四个相邻成正方形的元素的右下角元素来记录当前可形成的最大的正方形的边长,且边长选择为上、左和上左数值中的最小值,这样就可以确定之前已计算过的二维矩阵数组中所能形成的最大公共面积。初步使用二维数组来保存所有的数据信息,后来发现其实每一次判断时,其实都只是当前元素和当前元素的上、左、上左元素所形成的四元素正方形内的操作,所以只需要两个一维数组来保存当前列和前一列的数据信息就可以了,这样可以大大的降低算法的时间复杂度和空间复杂度。
代码:
int maximalSquare(vector<vector<char>>& matrix) {
//解法一:创建二维数组求解(效率为10%左右)
if(!matrix.size()) return matrix.size();
int max = 0;
int dp[matrix.size()][matrix[0].size()];
memset(dp, 0, sizeof(dp));
//初始化记录数组第一行元素
for(int i = 0; i < matrix[0].size(); i++){
dp[0][i] = matrix[0][i] - 48;
max = matrix[0][i] == 49 ? 1 : max;
}
//初始化记录数组第一列元素
for(int i = 0; i < matrix.size(); i++){
dp[i][0] = matrix[i][0] - 48;
max = matrix[i][0] == 49 ? 1 : max;
}
//对二位矩阵数组进行遍历
for(int i = 1; i < matrix.size(); i++){
for(int j = 1; j < matrix[i].size(); j++){
dp[i][j] = matrix[i][j] - 48;
//如果当前元素和当前元素的上、左和上左元素面积同时存在(>=1)
if(dp[i-1][j-1] && dp[i][j-1] && dp[i-1][j] && dp[i][j]){
//从上、左、上左相邻元素中选择最小公共边长并加一
dp[i][j] = min(min(dp[i-1][j-1], dp[i-1][j]), dp[i][j-1]) + 1;
//如果当前计算出的面积大于之前保存的面积即替换
max = dp[i][j] * dp[i][j] > max ? dp[i][j] * dp[i][j] : max;
}
}
}
return max;
//解法二:创建两个一维数组进行求解(效率为96%左右)
if(matrix.empty()) return 0;
//初始化保存二维矩阵的行数和列数,sz为最大边长
int row = matrix.size(); int col = matrix[0].size(); int sz = 0;
//创建一维数组保存当前和前一列的数据
vector<int> pre(row, 0), cur(row, 0);
//初始化pre数组用于保存前一列的数据
for(int i = 0; i < row; i++){
pre[i] = matrix[i][0] - '0';
sz = max(pre[i], sz);
}
//外层按列遍历
for(int i = 1; i < col; i++){
//初始化每一列的首元素
cur[0] = matrix[0][i] - '0';
sz = max(cur[0], sz);
//内层按行进行遍历
for(int j = 1; j < row; j++){
if(matrix[j][i] == '1'){
//pre为前一列,cur为当前列,cur[j]为当前操作元素
cur[j] = min(cur[j-1], min(pre[j-1], pre[j])) + 1;
sz = max(cur[j], sz);
}else{
cur[j] = 0;
}
}
//遍历完成后,将当前列赋值给pre数组保存
pre = cur;
}
return sz * sz;
}