2021-06-26:给定一个只有0和1组成的二维数组,返回边框全是1的最大正方形面积。
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
}
执行结果如下:
公众号:福大大架构师每日一题