2021-06-26:给定一个只有0和1组成的二维数组,返回边框全是1的最大正方形面积。
福大大 答案2021-06-26:
1.自然智慧。遍历每个点,复杂度是O(N2)。每个点往右下看的从1到n正方形,复杂度是O(N),每个正方形,判断边框是否为1,复杂度是O(N)。所以总体时间复杂度是O(N4),额外空间复杂度是O(1)。
2.每个正方形的边框是否为1的优化。时间复杂度可以优化成O(1)。准备两个二维数组。一个二维数组,记录dpToRight[i][j],表示当前点往右看的1的个数。另一个二维数组,记录dpToDown[i][j],表示当前点往下看的1的个数。将近一天的研究,以为时间复杂度可以优化成O(N2),但实际上并不能,至少我目前没想出来。时间复杂度是O(N3),额外空间复杂度是O(N**2)。
代码用golang编写。代码如下:
package main import ( "fmt" ) func main() { grid := [][]int{ {0, 1, 1, 1, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 1, 1, 1, 0, 1, 1}, {1, 1, 1, 1, 0, 1, 1, 1}, {1, 0, 1, 0, 0, 1, 1, 1}, {0, 1, 1, 1, 1, 0, 1, 1}, } largest1BorderedSquare1(grid) largest1BorderedSquare2(grid) } func printGrid(grid [][]int) { return N := len(grid) M := len(grid[0]) for i := 0; i < N; i++ { for j := 0; j < M; j++ { fmt.Print(grid[i][j], " ") } fmt.Println("") } fmt.Println("--------") } func largest1BorderedSquare1(grid [][]int) int { ans := 0 N := len(grid) M := len(grid[0]) ans = largest1BorderedSquare11(grid) gridCopy := make([][]int, N) for i := 0; i < N; i++ { gridCopy[i] = make([]int, M) } //左右翻转 for i := 0; i < N; i++ { for j := 0; j < M; j++ { gridCopy[i][j] = grid[i][M-j-1] } } ans = getMax(ans, largest1BorderedSquare11(gridCopy)) //上下翻转 for i := 0; i < N; i++ { for j := 0; j < M; j++ { gridCopy[i][j] = grid[N-i-1][j] } } ans = getMax(ans, largest1BorderedSquare11(gridCopy)) //左右翻转,上下翻转 for i := 0; i < N; i++ { for j := 0; j < M; j++ { gridCopy[i][j] = grid[N-i-1][M-j-1] } } ans = getMax(ans, largest1BorderedSquare11(gridCopy)) if ans > 0 { ans = largest1BorderedSquare22(grid, ans) } fmt.Println(ans * ans) return ans * ans } func largest1BorderedSquare11(grid [][]int) int { N := len(grid) M := len(grid[0]) printGrid(grid) //内部从右往左,外部从下往上 dpToRight := make([][]int, N) for i := 0; i < N; i++ { dpToRight[i] = make([]int, M) } for i := N - 1; i >= 0; i-- { temp := 0 for j := M - 1; j >= 0; j-- { if grid[i][j] == 0 { temp = 0 } else { temp++ } dpToRight[i][j] = temp } } printGrid(dpToRight) //内部从右往左,外部从下往上 dpToDown := make([][]int, N) for i := 0; i < N; i++ { dpToDown[i] = make([]int, M) } for j := M - 1; j >= 0; j-- { temp := 0 for i := N - 1; i >= 0; i-- { if grid[i][j] == 0 { temp = 0 } else { temp++ } dpToDown[i][j] = temp } } printGrid(dpToDown) ans := 0 //左上位置,朝右下看 for i := 0; i < N; i++ { for j := 0; j < M; j++ { //dp[i][j]是左上点 //获取最小值 edge := getMin(dpToRight[i][j], dpToDown[i][j]) //左上点求小边 //右上点 左下点 if edge > 0 && dpToDown[i][j+edge-1] >= edge && //右上点朝下看 dpToRight[i+edge-1][j] >= edge { //左下点朝右看 ans = getMax(ans, edge) } } } return ans } func largest1BorderedSquare22(grid [][]int, ans int) int { N := len(grid) M := len(grid[0]) printGrid(grid) //内部从右往左,外部从下往上 dpToRight := make([][]int, N) for i := 0; i < N; i++ { dpToRight[i] = make([]int, M) } for i := N - 1; i >= 0; i-- { temp := 0 for j := M - 1; j >= 0; j-- { if grid[i][j] == 0 { temp = 0 } else { temp++ } dpToRight[i][j] = temp } } printGrid(dpToRight) //内部从右往左,外部从下往上 dpToDown := make([][]int, N) for i := 0; i < N; i++ { dpToDown[i] = make([]int, M) } for j := M - 1; j >= 0; j-- { temp := 0 for i := N - 1; i >= 0; i-- { if grid[i][j] == 0 { temp = 0 } else { temp++ } dpToDown[i][j] = temp } } printGrid(dpToDown) //左上位置,朝右下看 for i := 0; i < N; i++ { for j := 0; j < M; j++ { //dp[i][j]是左上点 //获取最小值 edge := getMin(dpToRight[i][j], dpToDown[i][j]) //左上点求小边 //右上点 左下点 for k := edge - 1; k >= ans+1; k-- { if dpToDown[i][j+k-1] >= k && //右上点朝下看 dpToRight[i+k-1][j] >= k { //左下点朝右看 ans = getMax(ans, k) break } } } } return ans } func getMax(a int, b int) int { if a > b { return a } else { return b } } func getMin(a int, b int) int { if a < b { return a } else { return b } } func largest1BorderedSquare2(grid [][]int) int { N := len(grid) M := len(grid[0]) printGrid(grid) //内部从右往左,外部从下往上 dpToRight := make([][]int, N) for i := 0; i < N; i++ { dpToRight[i] = make([]int, M) } for i := N - 1; i >= 0; i-- { temp := 0 for j := M - 1; j >= 0; j-- { if grid[i][j] == 0 { temp = 0 } else { temp++ } dpToRight[i][j] = temp } } printGrid(dpToRight) //内部从右往左,外部从下往上 dpToDown := make([][]int, N) for i := 0; i < N; i++ { dpToDown[i] = make([]int, M) } for j := M - 1; j >= 0; j-- { temp := 0 for i := N - 1; i >= 0; i-- { if grid[i][j] == 0 { temp = 0 } else { temp++ } dpToDown[i][j] = temp } } printGrid(dpToDown) ans := 0 //左上位置,朝右下看 for i := 0; i < N; i++ { for j := 0; j < M; j++ { //dp[i][j]是左上点 //获取最小值 edge := getMin(dpToRight[i][j], dpToDown[i][j]) //左上点求小边 //右上点 左下点 for k := edge; k >= ans+1; k-- { if dpToDown[i][j+k-1] >= k && //右上点朝下看 dpToRight[i+k-1][j] >= k { //左下点朝右看 ans = getMax(k, ans) break } } } } fmt.Println(ans * ans) return ans }
执行结果如下: