题目类型描述: 给出一个二维的字母板和一个单词,寻找字母板网格中是否存在这个单词(单词可以由按顺序的相邻单元的字母组成,其中相邻单元指的是水平或者垂直方向相邻。每个单元中的字母最多只能使用一次)。
假设有这样一个二维字母表(如图)和单词“ABCCED”:
有如下路径存在:
我们应该返回“true”。
可以根据题给的二维字母表构建这样的二维boolean型数组,通过查找上下左右四个方向的字母,深度遍历。
不过我们需要清楚一点,我们在遍历的时候往往在做重复工作(检验上下左右四个字母是否符合要求),而且逐层深入,故考虑递归,将大问题划分为一个个小问题解决。分析时我们发现每个“小问题”都包含这两个操作:
代码如下:
package lint_code5;
public class Solution123 {
public static void main(String args[]){
char[][] board=new char[3][4];
board[0]="ABCE".toCharArray();
board[1]="SFCS".toCharArray();
board[2]="ADEE".toCharArray();
print(board);//构建字母表
System.out.println(exist(board, "ABCCED"));
}
public static boolean exist(char[][] board, String word) {//功能函数
// 排除特殊情况
if(board.length==0||word.length()==0||board==null||word=="") return false;
//构建同等的真值表
boolean[][] check=new boolean[board.length][board[0].length];
for(int i=0;i<board.length;i++)
for(int j=0;j<board[0].length;j++)//双循环表示字母表的每个位置都要检查(不过有的地方因为第一个字母就不符合,所以很快舍弃,不太耽误运行时间)
if(DFS(board, check, word, i, j, 0))
return true;
return false;
}
public static boolean DFS(char[][] b, boolean[][] c, String word, int i, int j, int wordIndex){//wordIndex:表示当前单词的检索位置
if(wordIndex>=word.length()) return true;
if(i>=c.length||j>=b[0].length||i<0||j<0) return false;
if(c[i][j]) return false;
if(b[i][j]!=word.charAt(wordIndex)) return false;
c[i][j]=true;
//递归
if(DFS(b, c, word, i+1, j, wordIndex+1)) return true;
if(DFS(b, c, word, i-1, j, wordIndex+1)) return true;
if(DFS(b, c, word, i, j+1, wordIndex+1)) return true;
if(DFS(b, c, word, i, j-1, wordIndex+1)) return true;
//回溯
c[i][j]=false;//如果它相邻位置字母仍不符合要求,应该归还该位置为false,
return false;
}
//print检验
public static void print(char[][] c){
for(int i=0;i<c.length;i++){
for(int j=0;j<c[0].length;j++)
System.out.print(c[i][j]+", ");
System.out.println();
}
}
public static void print(boolean[][] c){
for(int i=0;i<c.length;i++){
for(int j=0;j<c[0].length;j++)
System.out.print(c[i][j]+", ");
System.out.println();
}
}
}
DFS(深度优先遍历)在思考方式上和DP(动态规划)问题感觉差别不大,核心都是递归,注意理解。