问题描述:
给定一个字符类型的二维数组board,和一个字符串组成的列表words。可以从board任何位置出发,每一步可以走向上、下、左、右,四个方向,但是一条路径已经走过的位置,不能重复走。返回words哪些单词可以被走出来。
例子
board = [
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
]
words = ["oath","pea","eat","rain"]
输出:["eat","oath"]
代码:
public static class TrieNode {
public TrieNode[] nexts;
public int pass;
public int end;
public TrieNode() {
nexts = new TrieNode[26];
pass = 0;
end = 0;
}
}
public static void fillWord(TrieNode node, String word) {
node.pass++;
char[] chs = word.toCharArray();
int index = 0;
for (int i = 0; i < chs.length; i++) {
index = chs[i] - 'a';
if (node.nexts[index] == null) {
node.nexts[index] = new TrieNode();
}
node = node.nexts[index];
node.pass++;
}
node.end++;
}
public static String generatePath(LinkedList<Character> path) {
char[] str = new char[path.size()];
int index = 0;
for (Character cha : path) {
str[index++] = cha;
}
return String.valueOf(str);
}
public static List<String> findWords(char[][] board, String[] words) {
TrieNode head = new TrieNode();//前缀树最顶端的头
HashSet<String> set = new HashSet<>();
for (String word : words) {
if (!set.contains(word)) {
fillWord(head, word);
set.add(word);
}
}
//答案
List<String> res = new ArrayList<>();
//沿途走过的字符,收集起来存在path中
LinkedList<Character> path = new LinkedList<>();
for (int row = 0; row < board.length; row++) {
for (int col = 0; col < board[0].length; col++) {
//枚举board中的所有位置
//每一个位置出发的情况下,答案都收集
process(board, row, col, path, head, res);
}
}
return res;
}
//从board[row][col]位置的字符出发
//之前的路径上,走过的字符记录在path中
//cur还没有登上,有待检查能不能登上去的前缀树的节点
//如果找到words中的某个str,就记录在res中
//返回值从row,col出发,一共找到多少个str
public static int process(char[][] board, int row, int col, LinkedList<Character> path, TrieNode cur, List<String> res) {
char cha = board[row][col];
if (cha == 0) {//这个row col位置是之前走过的位置
return 0;
}
//(row,col)不是回头路
int index = cha - 'a';
//如果没路,或者这条路上最终的字符串之前加入过结果中
if (cur.nexts[index] == null || cur.nexts[index].pass == 0) {
return 0;
}
//没有走回头路,且能登上去
cur = cur.nexts[index];
path.addLast(cha);//当前位置的字符添加到路径里去
int fix = 0;//从row和col位置出发,后序一共搞定多少答案
//当我来到row col位置,如果决定不往后走了。是不是已经搞定某个字符串了
if (cur.end > 0) {
res.add(generatePath(path));
cur.end--;
fix++;
}
//往上下左右四个方向尝试
board[row][col] = 0;
if (row > 0) {
fix += process(board, row - 1, col, path, cur, res);
}
if (row < board.length - 1) {
fix += process(board, row + 1, col, path, cur, res);
}
if (col > 0) {
fix += process(board, row, col - 1, path, cur, res);
}
if (col < board[0].length - 1) {
fix += process(board, row, col + 1, path, cur, res);
}
board[row][col] = cha;
path.pollLast();
cur.pass -= fix;
return fix;
}
public static void main(String[] args) {
char[][] board = {
{'o','a','a','n'},
{'e','t','a','e'},
{'i','h','k','r'},
{'i','f','l','v'}
};
String[] words = {"oath","pea","eat","rain"};
List<String> ans = findWords(board,words);
System.out.println(ans);
}