这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战
题目
给你一个大小为 m x n 的整数矩阵 isWater ,它代表了一个由 陆地 和 水域 单元格组成的地图。
如果 isWater[i][j] == 0 ,格子 (i, j) 是一个 陆地 格子。
如果 isWater[i][j] == 1 ,格子 (i, j) 是一个 水域 格子。
你需要按照如下规则给每个单元格安排高度:
每个格子的高度都必须是非负的。
如果一个格子是是 水域 ,那么它的高度必须为 0 。
任意相邻的格子高度差 至多 为 1 。当两个格子在正东、南、西、北方向上相互紧挨着,就称它们为相邻的格子。(也就是说它们有一条公共边)
找到一种安排高度的方案,使得矩阵中的最高高度值 最大 。
请你返回一个大小为 m x n 的整数矩阵 height ,其中 height[i][j] 是格子 (i, j) 的高度。如果有多种解法,请返回 任意一个 。
示例
输入:isWater = [[0,1],[0,0]]
输出:[[1,0],[2,1]]
解释:上图展示了给各个格子安排的高度。
蓝色格子是水域格,绿色格子是陆地格。
输入:isWater = [[0,0,1],[1,0,0],[0,0,0]]
输出:[[1,1,0],[0,1,1],[1,2,2]]
解释:所有安排方案中,最高可行高度为 2 。
任意安排方案中,只要最高高度为 2 且符合上述规则的,都为可行方案。
提示
m == isWater.lengthn == isWater[i].length1 <= m, n <= 1000isWater[i][j]要么是0,要么是1。- 至少有 1 个水域格子。
解题思路
定义一个结果数组,先根据陆地或者水域做一个初始化的填充。
然后,我们从左上到右下,先遍历一遍,计算出一个左侧的最小值。再从右下到左上,计算出右侧的最小值,取两者间的最小值才能得出全局最小值。
例如:[1,0,0,0,0,1],左侧计算结果为[0,1,2,3,4,0],右侧计算结果为[0,4,3,2,1,0]。单次遍历的最大高度均为4,这个结果肯定是错误的,两边结合后可得[0,1,2,2,1,0]。
代码实现
class Solution {
public int[][] highestPeak(int[][] isWater) {
int m = isWater.length, n = isWater[0].length;
int[][] land = new int[m][n];
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
if(isWater[i][j] == 1){
// 是水域,高度为 1
land[i][j] = 0;
}else{
// 陆地,初始化为边界
land[i][j] = 1000 * 1000;
}
}
}
// 左侧遍历
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
if(isWater[i][j] == 0){
int height = land[i][j];
if(i > 0){
height = Math.min(land[i - 1][j] + 1, height);
}
if(j > 0){
height = Math.min(land[i][j - 1] + 1, height);
}
land[i][j] = height;
}
}
}
// 右侧遍历
for(int i = m - 1; i >= 0; --i){
for(int j = n - 1; j >= 0; --j){
if(isWater[i][j] == 0){
int height = land[i][j];
if(i < m - 1){
height = Math.min(land[i + 1][j] + 1, height);
}
if(j < n - 1){
height = Math.min(land[i][j + 1] + 1, height);
}
land[i][j] = height;
}
}
}
return land;
}
}