二维平面上使用回溯算法
LeetCode79 单词搜索
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
给定 word = "ABCCED", 返回 true
给定 word = "SEE", 返回 true
给定 word = "ABCB", 返回 false
来源:力扣(LeetCode 79)
class Solution {
boolean[][] isVisited;
//为了移动方便设置的偏移量数组
int[][] d={{0,1},{1,0},{0,-1},{-1,0}};
public boolean inArea(int newx,int newy,char[][] board){
return newx>=0&&newx<board.length&&newy>=0&&newy<board[0].length;
}
//从board[startx][starty]开始 去找从index开始的所有字母在board当中能不能被找见
public boolean searchWord(char[][] board,String word,int startx,int starty,int index){
//index表示单词的下标索引
//这个if表示单词的全部字母找到
if(word.length()-1==index){
return board[startx][starty]==word.charAt(index);
}
if(board[startx][starty]==word.charAt(index)){
isVisited[startx][starty]=true;
for(int i=0;i<4;i++){
int newx=startx+d[i][0];
int newy=starty+d[i][1];
//如果新的座标没有被访问过而且没有越界
if(inArea(newx,newy,board)&&!isVisited[newx][newy]){
if(searchWord(board,word,newx,newy,index+1))
return true;
}
}
//如果上下左右都没有 回溯
isVisited[startx][starty]=false;
}
return false;
}
public boolean exist(char[][] board, String word) {
isVisited=new boolean[board.length][board[0].length];
//循环遍历这个二维数组的每一个位置去search
for(int i=0;i<board.length;i++){
for(int j=0;j<board[i].length;j++){
if(searchWord(board,word,i,j,0))
return true;
}
}
//双重循环把所有位置遍历完成之后 依然没有找到 说明该网格没有这个单词
return false;
}
}
LeetCode200 岛屿数量
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
输入:
11000
11000
00100
00011
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。
输入:
11110
11010
11000
00000
输出: 1
class Solution {
int[][] move={{0,1},{1,0},{0,-1},{-1,0}};
int m,n;
boolean[][] visited;
public boolean inArea(int x,int y){
return x>=0&&x<m&&y>=0&&y<n;
}
//从grid[x][y]开始进行floodfill算法
//把和这个1水平或竖直方向相连的所有地区标记成一块
public void dfs(char[][] grid,int x,int y){
visited[x][y]=true;
for(int i=0;i<4;i++){
int newx=x+move[i][0];
int newy=y+move[i][1];
if(inArea(newx,newy)&&!visited[newx][newy]&&grid[newx][newy]=='1'){
dfs(grid,newx,newy);
}
}
return;
}
public int numIslands(char[][] grid) {
m=grid.length;
if(m==0) return 0;
n=grid[0].length;
visited=new boolean[m][n];
//定义res存储这个地图有多少个岛屿
int res=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(grid[i][j]=='1'&&!visited[i][j]){
res+=1;
//每次找到一个地区之后 把和该地区相连的所有1地区
//全部标记成为一块区域 这些地区组成1块岛屿
//dfs的任务就是把和这个1水平或竖直方向相连的所有地区标记成一块
dfs(grid,i,j);
}
}
}
return res;
}
}
LeetCode130 被围绕的区域
给定一个二维的矩阵,包含 ‘X’ 和 ‘O’(字母 O)。
找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。
示例:
X X X X
X O O X
X X O X
X O X X
运行你的函数后,矩阵变为:
X X X X
X X X X
X X X X
X O X X
解释:
被围绕的区间不会存在于边界上,换句话说,任何边界上的 ‘O’ 都不会被填充为 ‘X’。 任何不在边界上,或不与边界上的 ‘O’ 相连的 ‘O’ 最终都会被填充为 ‘X’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
来源:力扣(LeetCode 130)
class Solution {
int[][] move={{0,1},{1,0},{0,-1},{-1,0}};
int m,n;
boolean[][] visited;
public boolean inArea(int x,int y){
return x>=0&&x<m&&y>=0&&y<n;
}
public void dfs(char[][] board,int x,int y,boolean[][] visited){
visited[x][y]=true;
//找这个位置的上下左右四个方向
for(int i=0;i<4;i++){
int newx=x+move[i][0];
int newy=y+move[i][1];
if(inArea(newx,newy)&&!visited[newx][newy]&&board[newx][newy]=='O'){
dfs(board,newx,newy,visited);
}
}
return;
}
public void solve(char[][] board) {
//m表示行
m=board.length;
if(m==0)
return;
//n表示列
n=board[0].length;
visited=new boolean[m][n];
if(m==0||m==0)
return;
for(int i=0;i<n;i++){
//第一行
if(board[0][i]=='O') dfs(board,0,i,visited);
//最后一行
if(board[m-1][i]=='O') dfs(board,m-1,i,visited);
}
for(int j=0;j<m;j++){
//最左列
if(board[j][0]=='O') dfs(board,j,0,visited);
//最右列
if(board[j][n-1]=='O') dfs(board,j,n-1,visited);
}
//通过以上的4个if 把边界上的O和与边界上的O相邻的所有的O找到
//并且把他们标记为true
//双重循环遍历整个数组 如果board[i][j]的元素为O而且这个O不在边界 不和边界的O相邻
//那么此时的O就是我们要替换成X的O 我们替换即可
for(int i=0;i<m;i++){
for( int j=0;j<n;j++){
if(board[i][j]=='O'&&!visited[i][j]){
board[i][j]='X';
}
}
}
return;
}
}