你现在手里有一份大小为 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])