算法原理
FloodFill算法 中文:洪水灌溉
其实本质就是找出性质相同的联通块

这一类问题的解决需要依靠搜索算法中很重要的bfs(宽度优先遍历)/dfs(深度优先遍历)
这里我们利用bfs来解决FloodFill问题
题目解析
1.图像渲染
题目描述
给定一个m*n的二维整数数组表示图画image,其中image[i][j] 表示该图画的像素值大小,给定三个整数,sr,sc和color 你应该从image[sr][sc] 开始对图像进行上色填充
为了完成上色工作:1.从初始像素开始,将其颜色改为color 2.对初始坐标的上下左右四个方向上相邻且与初始像素的原始颜色同色的像素点执行相同操作
3.通过检查与初始像素的原始颜色相同的相邻像素并修改其颜色来继续重复此过程
4,当没有其他原始颜色相邻像素时停止操作
最终返回经过上色渲染修改后的图像
算法原理
从给定位置的像素点开始,如果像素点本身的颜色与给定的颜色相同,直接返回原数组

这里队列存的是坐标,出队列即要修改颜色,并将其上下左右遍历,满足条件的加入队列
代码实现
java
class Solution {
int[] dx={1,-1,0,0};
int[] dy={0,0,1,-1};
public int[][] floodFill(int[][] image, int sr, int sc, int color) {
int prev=image[sr][sc];
if(prev==color){
return image;
}
int m=image.length;
int n=image[0].length;
Queue<int[]> q=new LinkedList<>();
q.add(new int[]{sr,sc});
while(!q.isEmpty()){
int[] t=q.poll();
int a=t[0],b=t[1];
image[a][b]=color;
for(int k=0;k<4;k++){
int x=a+dx[k],y=b+dy[k];
if(x>=0&&x<m&&y>=0&&y<n&&image[x][y]==prev){
q.add(new int[]{x,y});
}
}
}
return image;
}
}
2.岛屿数量
题目描述
给定一个由'1'(陆地)和'0'(水)组成的二维网络,请你计算网络中岛屿的数量
岛屿总是被水包围,并且每座岛屿只能由水平方向和或竖直方向上相邻的陆地连接形成
此外,你可以假设该网络的四条边均被水包围
算法原理
这里我们和上道题类似,还是使用队列,同时还要使用向量数组

代码实现
java
class Solution {
int[] dx={1,-1,0,0};
int[] dy={0,0,1,-1};
boolean[][] vis=new boolean[301][301];
int m,n;
public int numIslands(char[][] grid) {
m=grid.length;
n=grid[0].length;
int ret=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(grid[i][j]=='1'&&!vis[i][j]){
ret++;
bfs(grid,i,j);
}
}
}
return ret;
}
public void bfs(char[][] g,int i,int j){
Queue<int[]> q=new LinkedList<>();
vis[i][j]=true;
q.add(new int[]{i,j});
while(!q.isEmpty()){
int[] t=q.poll();
int a=t[0],b=t[1];
for(int k=0;k<4;k++){
int x=a+dx[k],y=b+dy[k];
if(x>=0&&x<m&&y>=0&&y<n&&g[x][y]=='1'&&!vis[x][y]){
q.add(new int[]{x,y});
vis[x][y]=true;
}
}
}
}
}
3.岛屿的最大面积
题目描述
给定一个大小为m*n的二进制矩阵grid
岛屿是由一些相邻的1(代表土地)构成的组合,这里的相邻要求两个1必须在水平竖直的四个方向上相邻,你可以假设grid的四个边缘都被0(代表水)包围着
算法原理
这里利用bfs,先扫描矩阵,当遇到一个没遍历过的,将vis改为false,多加一个count来维护面积
代码实现
java
class Solution {
int[] dx=new int[]{0,0,1,-1};
int[] dy=new int[]{1,-1,0,0};
boolean[][] vis=new boolean[51][51];
int m,n;
public int maxAreaOfIsland(int[][] grid) {
m=grid.length;
n=grid[0].length;
int ret=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(grid[i][j]==1&&!vis[i][j]){
ret=Math.max(ret,bfs(grid,i,j));
}
}
}
return ret;
}
public int bfs(int[][] grid,int i,int j){
int result=0;
Queue<int[]> q=new LinkedList<>();
q.offer(new int[]{i,j});
result++;
vis[i][j]=true;
while(!q.isEmpty()){
int[] t=q.poll();
int a=t[0],b=t[1];
for(int k=0;k<4;k++){
int x=a+dx[k],y=b+dy[k];
if(x>=0&&x<m&&y>=0&&y<n&&grid[x][y]==1&&!vis[x][y]){
q.offer(new int[]{x,y});
vis[x][y]=true;
result++;
}
}
}
return result;
}
}
4.被围绕的区域
题目描述
给定一个m*n的矩阵board,有若干个'x'和'o'组成,捕获所有被围绕的区域
连接:一个单元格与水平竖直方向上相邻的单元格连接
区域:连接所有'o'的单元格形成的一个区域
围绕:如果你可以用'x'单元格连接这个区域,并且这个区域中没有单元格位于board边缘,则这个区域被'x'单元格围绕
通过原地将矩阵中所有的'0'替换为'x'来捕获被围绕的区域,你不需要返回任何值
算法原理
解法一:直接做(但我们需要考虑这个位置是否被修改过,比较麻烦)
解法二:正难则反
这道题与之前用bfs解决FloodFill算法不同的是,这道题边缘的是不能修改的
这些位于边缘的o影响我们bfs
那我们就可以将边缘的o改为无关字符,再bfs其他部分,将0改为x,然后再把边缘改的修改回来即可
代码实现
java
class Solution {
int[] dx=new int[]{1,-1,0,0};
int[] dy=new int[]{0,0,1,-1};
int m,n;
public void solve(char[][] board) {
m=board.length;
n=board[0].length;
//1.先遍历四边,把'0'改为'.
for(int j=0;j<n;j++){
if(board[0][j]=='O'){
bfs(board,0,j);
}
if(board[m-1][j]=='O'){
bfs(board,m-1,j);
}
}
for(int i=0;i<m;i++){
if(board[i][0]=='O'){
bfs(board,i,0);
}
if(board[i][n-1]=='O'){
bfs(board,i,n-1);
}
}
//2.还原
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(board[i][j]=='O'){
board[i][j]='X';
}
if(board[i][j]=='.'){
board[i][j]='O';
}
}
}
}
public void bfs(char[][]board,int i,int j){
Queue<int[]> q=new LinkedList<>();
q.offer(new int[]{i,j});
board[i][j]='.';
while(!q.isEmpty()){
int[] t=q.poll();
int a=t[0],b=t[1];
for(int k=0;k<4;k++){
int x=a+dx[k],y=b+dy[k];
if(x>=0&&x<m&&y>=0&&y<n&&board[x][y]=='O'){
q.offer(new int[]{x,y});
board[x][y]='.';
}
}
}
}
}