暴力破解是最容易想到的,比如这个leetcode题目。原题地址
在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。
示例:
输入:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
输出: 4
题目很好理解。我首先想到的是暴力破解,思路是遍历二维数组,遇到1时,就在此基础上逐层往外扩展,直到达到边界,或者扩展过程中遇到0。
public int maximalSquare(char[][] matrix) {
if(null == matrix || matrix.length == 0) return 0;
int row = matrix.length;
int len = matrix[0].length;
int res = 0;
for(int i = 0; i < row; i++){
for(int j = 0; j < len; j++){
if(matrix[i][j] == '1'){
int level = 1; // 往外扩展的层数
while(i + level < row && j + level < len){
if(testOver(i,j,level,matrix)){
level++;
}else{
break;
}
}
res = Math.max(res, level*level);
}
}
}
return res;
}
/*
*左上角的行列值row与len, 往外扩展的第几层。
*/
private boolean testOver(int row, int len, int level, char[][] matrix){
boolean result = true;
// 外扩展一列值的判断
for(int i = row; i <= row + level; i++ ){
if(matrix[i][len + level] == '0'){
return false;
}
}
// 下扩展一行的判断
for(int i = len; i < len+level; i++){
if(matrix[row + level][i] == '0'){
return false;
}
}
return true;
}
这个可以解决问题,空间复杂度为O(1),时间复杂度比较高,远远大于O(mn)—行列值分别为m和n。若m和n中,较小的一个计为x,那总的时间复杂度就是O(mn)*O(x2)。
有没有什么方法,可以降低时间复杂度呢?真有,动态规划,只是这个状态转移方程,不好想。我也是看了官方的题解才知道的。
结合图, dp(i,j) 表示以 以(i, j)为右下角,符合条件的正方形边长的最大值。仔细看
dp[i][j-1]和dp[i-1][j]和dp[i-1][j-1] 这三个中的最小值 + 1 = dp[i][j]。知道这个,代码就很容易写了。
public int maximalSquare(char[][] matrix) {
if(null == matrix || matrix.length == 0) return 0;
int row = matrix.length;
int len = matrix[0].length;
int[][] dp = new int[row][len];
int res = 0;
for(int i = 0; i < row; i++){
for(int j = 0; j < len; j++){
if(matrix[i][j] == '1'){
if(i == 0 || j ==0){
dp[i][j] = 1;
}else{
dp[i][j] = getMin(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1;
}
res = Math.max(res, dp[i][j]);
}
}
}
return res*res;
}
private int getMin(int a, int b, int c){
return Math.min(a, Math.min(b, c));
}
时间复杂度:O(mn) ,空间复杂度:O(mn),这样复杂度是可以接受的。
像这个题目,动态转移方程,想不到就是想不到,跟你写代码的水平没有关系。这个和你在这方面的思维训练有关。想不到也没什么,请相信,你并不孤独,我也想不到哈!
一旦我知道这个动态转移方程,我能撸出代码。