1. 算法原理
深度优先搜索(DFS):从某个起点出发,依次遍历每个未访问的邻接点,对每一个可能的分支路径深入到不能再深入为止。如下图:
2. 案例1——机器人的运动范围
(1)题目描述
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
(2)思路
1)从坐标(0,0)开始,向右、向下开始递归;
2)行超出索引、列超出索引、已遍历、不满足k的条件结束递归;
3)满足条件的标记坐标,范围+1,继续向右,向下递归。
(3)代码
/**
* @param m,n : 行和列
* @param k : 行数位之和(行拆分的每个数之和) + 列的数位之和(列拆分的每个数之和) <= k
* @return 能行走的范围大小(格子数量)
*/
int m,n,k;
boolean[][] visited;
public int movingCount(int m, int n, int k) {
//标记走过的坐标
boolean[][] visited = new boolean[m][n];
this.visited = visited;
this.m = m;
this.n = n;
this.k = k;
return dfs(0,0,0,0);
}
/**
* @param i,j :行和列
* @param si,sj : 行(列)的数位之和
* @return
*/
public int dfs(int i,int j,int si,int sj){
//终止条件 :行超出索引、列超出索引、已遍历、不满足k的条件
if(i>=m || j>=n || visited[i][j]==true || si+sj>k)
return 0;
visited[i][j] = true;//已遍历
//数位之和每逢进位会突变一次,进位时数位之和-8,没进位时数位之和+1
int temp_si = (i + 1) % 10 == 0 ? si - 8 : si + 1;//行数位之和
int temp_sj = (j + 1) % 10 == 0 ? sj - 8 : sj + 1;//列数位之和
return 1+dfs(i+1,j,temp_si,sj) + dfs(i,j+1,si,temp_sj);//向右,向下遍历
}
3. 案例2——矩阵中的路径
(1) 题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]
但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
(2) 思路
1)先在矩阵中找出第一个符合要求的字母,找到后进入递归;
2)标记访问过的元素,递归四个方向的,符合要求的递归下一个;
3)被标记的元素在访问完毕需要改回原值;
4) 找到包含所有字符的路径后,即找出的路径等于字符串长度时,返回true,否则返回false。
(3)代码
/**
* @param board 矩阵
* @param word 要求的字符串
*/
public boolean exist(char[][] board, String word) {
char[] chars = word.toCharArray();
for(int i=0;i<board.length;i++)
for(int j=0;j<board[0].length;j++){
if(board[i][j]==chars[0]){//找出第一个符合要求的
board[i][j]='/';//标记访问过
if(dfs(board,chars,i,j,1)){
return true;
}
board[i][j]=chars[0];//访问完毕需改回来
}
}
return false;
}
/**
* @param i,j 矩阵索引
* @param k 当前chars的索引
*/
public boolean dfs(char[][] board,char[] chars,int i,int j,int k){
//递归终止条件:找到路径
if(k==chars.length)
return true;
int[] x = {1,-1,0,0};
int[] y = {0,0,1,-1};
//递归四个方向
for(int p=0;p<4;p++){
int ix = i+x[p];
int jy = j+y[p];
if(ix<board.length&&ix>=0&&jy<board[0].length&&jy>=0&&board[ix][jy]==chars[k]) {//符合要求,递归下一个
board[ix][jy] = '/';//标记访问过
if(dfs(board, chars, ix, jy, k + 1)){
return true;
}
board[ix][jy]=chars[k];//访问完毕需改回来
}
}
return false;
}