有一首歌唱的是真应景,“可能我撞了南墙才会回头吧”。不要深刻的理解它,来,看字面意思。一直走,直到没路了,撞了南墙才回头。
这就是深度优先搜索。
从上面的描述来看,深度优先搜索就是找到当下如何做的可能性之后,继续下一步,直到走到尽头,即走到边界线,就回退。
只说不练还是太抽象,来看看这一个题目:
图像渲染:
题目描述:
给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newColor,让你重新上色这幅图像。
为了完成上色工作,从初始坐标开始,记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。最后返回经过上色渲染后的图像。
如上图,从初始坐标开始,修改颜色,搜索上下左右,判断新的位置是否符合要求。
具体代码实现:
class Solution {
int[][] pos={{0,-1},{0,1},{-1,0},{1,0}};
public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
if(image==null){
return image;
}
int row=image.length;
int col=image[0].length;
int[][] book=new int[row][col];
int oldColor=image[sr][sc];
dfs(image,row,col,sr,sc,newColor,oldColor,book);
return image;
}
public void dfs(int[][] images,int row,int col,int x,int y,int newColor,int oldColor,int[][] book){
images[x][y]=newColor;
book[x][y]=1; //设置标记,表示该点已经访问过了
for(int i=0;i<4;i++){
int nx=x+pos[i][0];
int ny=y+pos[i][1];
if(nx>=row|nx<0||ny>=col||ny<0) {
continue;
}
if(images[nx][ny]==oldColor&&book[nx][ny]==0){
dfs(images,row,col,nx,ny,newColor,oldColor,book);
}
}
}
}
说明:有四个方向,左右上下搜索: int[][] pos={{0,-1},{0,1},{-1,0},{1,0}};
到达新的位置,在以新的位置为核心展开搜索。设计一个标记,若该点已经访问过则不再进行访问。
引申相似题目:
被围绕的区域
给定一个二维的矩阵,包含 ‘X’ 和 ‘O’(字母 O)。
找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。
例:如图所示:
如图,打红勾的是会变成x的,其余的O是连通的,没有被X包围,还是为O.
可以将边界上的o以及与o联通的都不算做包围,只要把边界上的o以及与之联
通的o进行特殊处理,剩下的o替换成x即可。
对于边上的每一个o进行DFS扩散,先把边上的每一个o用特殊符号标记,在此我用了#,把和它相邻的o都替换为#,每一个新的位置都做相同的DFS操作
4.所有扩散结束之后,把#号的位置(和边界连通)还原为o,原来为o的位置(和边界不连通)替换为x即可。
代码实现:
public class DFSsolution {
int[][] pos={{0,-1},{0,1},{-1,0},{1,0}};
public void DFS(char[][] board,int row,int col,int x,int y){
board[x][y]='#';
for(int i=0;i<4;i++){
int nx=x+pos[i][0];
int ny=y+pos[i][1];
if(nx>=row||nx<0||ny>=col||ny<0)
continue;
//(nx,ny)和边连通,标记,以(nx,ny)为中心,继续搜索
if(board[nx][ny]=='O'){
DFS(board,row,col,nx,ny);
}
}
}
public void solve(char[][] board) {
if(board==null||board.length==0||board[0].length==0){
return;
}
int row=board.length;
int col=board[0].length;
//寻找第一列和最后一列
for(int i=1;i<row-1;i++){
if(board[i][0]=='O')
DFS(board,row,col,i,0);
else if(board[i][col-1]=='O')
DFS(board,row,col,i,col-1);
}
//寻找第一行和最后一行
for(int i=0;i<col;i++){
if(board[0][i]=='O')
DFS(board,row,col,0,i);
else if(board[row-1][i]=='O')
DFS(board,row,col,row-1,i);
}
for(int i=1;i<row;i++){
for(int j=1;j<col;j++){
if(board[i][j]=='O')
board[i][j]='X';
else if(board[i][j]=='#')
board[i][j]='O';
}}
}
}