leetcode 1162. 地图分析

你现在手里有一份大小为 N x N 的『地图』(网格) grid,上面的每个『区域』(单元格)都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地,你知道距离陆地区域最远的海洋区域是是哪一个吗?请返回该海洋区域到离它最近的陆地区域的距离。

我们这里说的距离是『曼哈顿距离』( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个区域之间的距离是 |x0 - x1| + |y0 - y1| 。

如果我们的地图上只有陆地或者海洋,请返回 -1。

示例 1:

输入:[[1,0,1],[0,0,0],[1,0,1]]
输出:2
解释: 
海洋区域 (1, 1) 和所有陆地区域之间的距离都达到最大,最大距离为 2。
示例 2:

输入:[[1,0,0],[0,0,0],[0,0,0]]
输出:4
解释: 
海洋区域 (2, 2) 和所有陆地区域之间的距离都达到最大,最大距离为 4。
 

提示:

1 <= grid.length == grid[0].length <= 100
grid[i][j] 不是 0 就是 1

 方法一:动态规划,由于是上下左右四个方向,我们进行两个方向的扫描,第一次从左上到右下(常见的问题,及每次只能向右或向下搜索),第二次反向扫描。具体地说:

两遍扫描:

第一遍从左上角开始扫描

判断是否是陆地,如果是陆地,距离更新为0
如果是海洋,判断上面和左面是不是陆地,更新到陆地的最小距离dp[i][j]=min(up,left)
第二遍从右下角扫描

如果是陆地,跳过;如果是海洋,判断右面和下面是不是陆地,更新到陆地的最小距离(此时dp[i][j]=min(dp[i][j],down,right))

更新海洋到陆地的最大距离,去dp的最大值。

class Solution(object):
    def maxDistance(self, grid):
        """
        :type grid: List[List[int]]
        :rtype: int
        """
        m,n=len(grid),len(grid[0])
        if m*n==0:
            return -1
        cnt=sum([sum(i) for i in grid])
        if cnt==m*n or cnt==0:
            return -1
        dp=[[1e10 for _ in range(m)] for _ in range(n)]
        def is_suit(i,j):
            if i>=0 and i<m and j>=0 and j<n:
                return 1
            return 0
        for i in range(m):
            for j in range(n):
                if grid[i][j]==1:
                    dp[i][j]=0
                else:
                    top=1e10
                    left=1e10
                    if is_suit(i-1,j) and dp[i-1][j]!=1e10:
                        top=dp[i-1][j]+1
                    if is_suit(i,j-1) and dp[i][j-1]!=1e10:
                        left=dp[i][j-1]+1
                    dp[i][j]=min(top,left)
        for i in range(m-1,-1,-1):
            for j in range(n-1,-1,-1):
                if grid[i][j]!=1:
                    down=1e10
                    right=1e10
                    if is_suit(i+1,j) and dp[i+1][j]!=1e10:
                        down=dp[i+1][j]+1
                    if is_suit(i,j+1) and dp[i][j+1]!=1e10:
                        right=dp[i][j+1]+1
                    dp[i][j]=min(dp[i][j],down,right)
        return max([max(i) for i in dp])
        
        

方法二:使用队列进行广度优先,维护同维数组flag记录当前是否遍历过,为了记录当前最小层数,需要维护同维数组tmp记录当前位置所处的层数。

class Solution(object):
    def maxDistance(self, grid):
        """
        :type grid: List[List[int]]
        :rtype: int
        """
        m,n=len(grid),len(grid[0])
        if m*n==0:
            return -1
        cnt=sum([sum(i) for i in grid])
        if cnt==m*n or cnt==0:
            return -1
        flag=[[0 for _ in range(m)] for _ in range(n)]
        tmp=[[1e10 for _ in range(m)] for _ in range(n)]
        queue=[]
        for i in range(m):
            for j in range(n):
                if grid[i][j]==1:
                    queue.append((i,j))
                    flag[i][j]=1
                    tmp[i][j]=0
        while queue:
            x,y=queue.pop(0)
            for i,j in [(x-1,y),(x+1,y),(x,y-1),(x,y+1)]:
                if i>=0 and i<m and j>=0 and j<n and flag[i][j]==0:
                    queue.append((i,j))
                    flag[i][j]=1
                    tmp[i][j]=tmp[x][y]+1
        return max([max(i) for i in tmp])

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值