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
}

执行结果如下:
图片


左神java代码