题目描述
给定一个N \times NN×N的矩阵matrix,在这个矩阵中,只有0和1两种值,返回边框全是1的最大正方形的边长长度、
例如
0 1 1 1 1
0 1 0 0 1
0 1 0 0 1
0 1 1 1 1
0 1 0 1 1
其中,边框全是1的最大正方形的大小为4 \times 44×4,所以返回4
[要求]
时间复杂度为O(n^3)O(n
3
),空间复杂度为O(n^2)O(n
2
)

思路1:枚举所有子矩阵,时间复杂度 O(nm) * O(nm)
基于 思路一可以变为 枚举所有“正方形矩阵”,这个时候如果我们能够知道 左上角A,左下角B ,右上角C 三个点的位置,并知道相应的边长,就可以在O(min(m,n)) 中得到答案
所以有了思路二:
对矩阵进行预处理
假设我们有两个矩阵 right ,down
right[i][j] 标示 arr[i][j] 点上,向右有多少个连续的1
down[i][j] 标示 arr[i][j] 点上,向下有多少个连续的1

已经知道的左上角,只需要求得 k = min(right ,down ) ,然后 使得
down[i][j+k] >=k && right[i+k][j] >=k 即可 保证 点 i,j 可以构成一个长度为k 的正方形
如果不是就进行收缩 k--
整体时间复杂度 O(N^3) 空间复杂度 O(N^2)

package main
import (
    "fmt"
    //"os"
    //"strconv"
    //"bufio"
)
type node struct {
    right int 
    down int 
}
func main(){
    var n int
    fmt.Scanf("%d",&n)
    arr := make([][]int,n)
    dp := make([][]node,n)
    for i:=0;i<n;i++{
        arr[i] = make([]int,n)
        dp[i] = make([]node,n)
        for j:=0;j<n;j++{
            fmt.Scanf("%d",&arr[i][j])
        }
    }
    //构造dp 数据记录当前点的 right,down 值,注意当前点如果为0 默认取0,不记录
    for i:=n-1;i>=0;i--{
        num := 0
        for j:=n-1;j>=0;j--{
            if arr[j][i] == 0{
                num = 0
                continue
            }
            dp[j][i].down = num
            num ++
        }
        num = 0
        for k:=n-1;k>=0;k--{
            if arr[i][k] == 0 {
                num = 0
                continue;
            }
            dp[i][k].right = num
            num++
        }
    }
    helper(arr,dp,n)
    return 
}
//对预处理好的数组进行计算
func helper(arr [][]int ,dp [][]node,n int ){
    res := 0
    for i:=0;i<n;i++{
        for j:=0;j<n;j++{
            if arr[i][j] == 0{
                continue
            }
            minLen := dp[i][j].right
            if minLen > dp[i][j].down{
                minLen = dp[i][j].down
            }
            //fmt.Println(minLen)
            for k:=minLen;k>=0;k--{
                //判断是否越界 本题中 理论不需要
                if i+k >=n || j+k >=n{
                    continue
                }

                //判断是否是正方形
                if dp[i+k][j].right >= k && dp[i][j+k].down >= k {
                    if k > res {
                        res = k
                        //一旦是了即可退出,因为第一个是的一定是这一轮最大的
                        break
                    }
                }
            }
        }
    }
    //记得加上自身
    if res != 0 {
        res += 1
    }
    fmt.Println(res)
    return 

}