LeetCode 542 01矩阵问题

原文地址:https://leileiluoluo.com/posts/leetcode-01matrix-problem.html

1 题目描述
给定一个元素只可为0或1的矩阵,对矩阵中每个元素,计算出该元素点与最近的元素0的距离(相邻两个元素的距离为1)。

例子1:
输入:
0   0   0
0   1   0
0   0   0
输出:
0   0   0
0   1   0
0   0   0

例子2:
输入:
0   0   0
0   1   0
1   1   1
输出:
0   0   0
0   1   0
1   2   1

注:
给定矩阵的元素个数不超过10000;
给定矩阵至少包含1个0;
相邻元素的连接方式只可为上、下、左、右。

题目出处:
https://leetcode.com/problems/01-matrix/

2 解决思路
针对图像识别的模式识别中,计算图像固定区域特征时,有积分图的概念。
解决本题时借用一下该概念,按如下步骤判断每个元素与最近的元素0的距离。
1)扫描一遍矩阵,对每个元素点计算其左上角所有元素点的数值之和,结果为一个和值矩阵,称之为sumGraph;
2)针对原始矩阵的某个元素点,计算与其最近的0元素的距离时,首先根据sumGraph计算在指定半径覆盖的方形区域内是否包含0(根据sumGraph计算出该区域元素值总和,若小于全1总和即包含0);
3)若该区域包含0,则在该区域找到合个0,并算出最近的距离;
4)若该区域不包含0,则扩大搜索半径,直至找到包含0的方形区域并按步骤3)计算出结果。
5)按如上2)-4)步骤扫描原始矩阵并计算结果,直至所有元素点计算完成,并返回结果矩阵。
注:
本文算法初试搜索半径为1,若此半径上下左右围起的方形区域不包含0,则将半径扩大一倍。
逐步扩大半径及全图扫描计算如下图所示。

3 golang实现代码
https://github.com/olzhy/leetcode/blob/master/542_01_Matrix/test.go

func updateMatrix(m [][]int) [][]int {  
    const MaxInt = 999999999  
  
    max := func(n1, n2 int) int {  
        if n1 >= n2 {  
            return n1  
        }  
        return n2  
    }  
  
    steps := func(x1, y1, x2, y2 int) int {  
        abs := func(a, b int) int {  
            c := a - b  
            if c < 0 {  
                return -c  
            }  
            return c  
        }  
        return abs(x1, x2) + abs(y1, y2)  
    }  
  
    containsZero := func(sumGraph [][]int, x, y, radius int) bool {  
        xMin, yMin, xMax, yMax := x-radius-1, y-radius-1, x+radius, y+radius  
        if xMax > len(sumGraph)-1 {  
            xMax = len(sumGraph) - 1  
        }  
        if yMax > len(sumGraph[0])-1 {  
            yMax = len(sumGraph[0]) - 1  
        }  
  
        sumAllNotZeros := MaxInt  
        sum := sumAllNotZeros  
        if xMin < 0 && yMin < 0 {  
            sumAllNotZeros = (xMax + 1) * (yMax + 1)  
            sum = sumGraph[xMax][yMax]  
        } else if xMin < 0 && yMin >= 0 {  
            sumAllNotZeros = (xMax + 1) * (yMax - yMin)  
            sum = sumGraph[xMax][yMax] - sumGraph[xMax][yMin]  
        } else if xMin >= 0 && yMin < 0 {  
            sumAllNotZeros = (xMax - xMin) * (yMax + 1)  
            sum = sumGraph[xMax][yMax] - sumGraph[xMin][yMax]  
        } else {  
            sumAllNotZeros = (xMax - xMin) * (yMax - yMin)  
            sum = sumGraph[xMax][yMax] - sumGraph[xMin][yMax] - sumGraph[xMax][yMin] + sumGraph[xMin][yMin]  
        }  
        return sum < sumAllNotZeros  
    }  
  
    findMinStepsAround := func(m [][]int, x, y, radius int) int {  
        xMin, yMin, xMax, yMax := x-radius, y-radius, x+radius, y+radius  
        if xMin < 0 {  
            xMin = 0  
        }  
        if yMin < 0 {  
            yMin = 0  
        }  
        if xMax > len(m)-1 {  
            xMax = len(m) - 1  
        }  
        if yMax > len(m[0])-1 {  
            yMax = len(m[0]) - 1  
        }  
        minSteps := MaxInt  
        for i := xMin; i <= xMax; i++ {  
            for j := yMin; j <= yMax; j++ {  
                if 0 == m[i][j] {  
                    steps := steps(x, y, i, j)  
                    if steps < minSteps {  
                        minSteps = steps  
                    }  
                }  
            }  
        }  
        return minSteps  
    }  
  
    findMinStepsWithScalingRadius := func(m, sumGraph [][]int, x, y int) (int, int) {  
        minRadius, maxRadius := 1, max(max(x, y), max(len(m)-1-x, len(m)-1-y))  
        minSteps := MaxInt  
        r := minRadius  
        for r = minRadius; r <= maxRadius; r *= 2 {  
            containsZero := containsZero(sumGraph, x, y, r)  
            if containsZero {  
                minSteps = findMinStepsAround(m, x, y, r)  
                if minSteps > r {  
                    continue  
                }  
                return minSteps, r  
            }  
        }  
        if maxRadius != r {  
            minSteps = findMinStepsAround(m, x, y, maxRadius)  
        }  
        return minSteps, r  
    }  
  
    sumGraph := func(m [][]int) [][]int {  
        sumGraph := make([][]int, len(m))  
        for i := range m {  
            sumGraph[i] = make([]int, len(m[i]))  
            for j := range m[i] {  
                sumGraph[i][j] = 0  
                if 0 == j && 0 == i {  
                    sumGraph[i][j] = m[i][j]  
                } else if 0 == j && i > 0 {  
                    sumGraph[i][j] = sumGraph[i-1][j] + m[i][j]  
                } else if j > 0 && 0 == i {  
                    sumGraph[i][j] = sumGraph[i][j-1] + m[i][j]  
                } else {  
                    sumGraph[i][j] = sumGraph[i][j-1] + sumGraph[i-1][j] - sumGraph[i-1][j-1] + m[i][j]  
                }  
            }  
        }  
        return sumGraph  
    }  
  
    sumG := sumGraph(m)  
    updated := make([][]int, len(m))  
    for i := range m {  
        updated[i] = make([]int, len(m[i]))  
        for j := range m[i] {  
            minSteps, _ := findMinStepsWithScalingRadius(m, sumG, i, j)  
            updated[i][j] = minSteps  
        }  
    }  
    return updated  
}  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值