733 . 图像渲染
示例 1:
输入:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
输出: [[2,2,2],[2,2,0],[2,0,1]]
解析:
在图像的正中间,(坐标(sr,sc)=(1,1)),
在路径上所有符合条件的像素点的颜色都被更改成2。
注意,右下角的像素没有更改为2,
因为它不是在上下左右四个方向上与初始点相连的像素点。
为了直观查看,将样例二维数组铺开:
1 1 1
1 1 0
1 0 1
此时我们从最中心的1入手
先将它的值改变为newColor
然后,再向四周遍历!
思想很简单,但我们知道,遍历不可能是永不停歇的,必须找到条件对遍历加以限制,否则代码将陷入死循环。
首先想到的,是下标不能越界,也就是超出二维数组的范围
然后,由于四周遍历的特性,导致上下之间的数会重复遍历,也就是我刚刚上去,一会又会下来,如果不能解决这个问题,代码会进入死循环。
还有一个条件,是题意告诉我们,我们只修改数字相同的一片数组,否则,程序执行完后,整个数组的值都会被涂抹成newColor。所以我们知道,值是否与最开始的image[sr][sc](下面把它称作oldColor)相等,也是一个边界条件。(到这里,这题已经基本解决了)
还有最后一个问题,如果newColor和oldColor相等,那会导致上一个条件失效,因为即使当前的值与oldColor相等,它也有可能是被遍历过的!而这会导致相邻位置来回反复遍历,造成死循环。这种情况有两种做法
if(arr[sr][sc] == newColor||arr[sr][sc] != oldColor) return ;
if(image[sr][sc] == newColor) return image;
到这里这道题就结束了,一道看似很简单的简单题,却有三个边界条件,还是值得好好琢磨的,广度搜索建立在递归的基础上,和递归一样,必须把边界条件控制好才行。
public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
dfs(image,sr,sc,image[sr][sc],newColor);
return image;
}
public void dfs(int[][] arr, int sr, int sc,int oldColor, int newColor)
{
if(sr>=arr.length||sr<0||sc>=arr[0].length||sc<0
||arr[sr][sc] == newColor||arr[sr][sc] != oldColor)
return ;
arr[sr][sc] = newColor;
dfs(arr,sr+1,sc,oldColor,newColor);
dfs(arr,sr-1,sc,oldColor,newColor);
dfs(arr,sr,sc+1,oldColor,newColor);
dfs(arr,sr,sc-1,oldColor,newColor);
}
200.岛屿数量
这道题和刚才的题很像,很像,一样是“感染”周围的元素,把它们变成和自己一样的数字,唯一的区别是多了一个遍历累加的操作。
public static void infect(char[][] grid,int i,int j,int x,int y) {
if (i < 0 || i >= x || j < 0 || j >= y ||grid[i][j] != '1')
return;
grid[i][j] = '2';
infect(grid,i+1,j,x,y);
infect(grid,i-1,j,x,y);
infect(grid,i,j+1,x,y);
infect(grid,i,j-1,x,y);
}
public static int numIslands(char[][] gird) {
if (gird == null || gird.length == 0)
return 0;
int x = gird.length;
int y = gird[0].length;
int res = 0;
for (int i = 0;i < x;i++ )
{
for (int j = 0;j < y;j++ )
{
if (gird[i][j] == '1')
{
res++;
infect(gird,i,j,x,y);
}
}
}
return res;
}