题目
给定一个 m x n 二维字符网格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”]
输入:board = [[“a”,“b”],[“c”,“d”]], words = [“abcb”]
输出:[]
解题
思路一:暴力求解
刚开始没思路,看题中数据量不是特别大,想直接暴力解了:每个单词,从每个节点开始向四周遍历,找到就返回;但是还是超时了
int[] nm = {-1, 1, 0, 0};
int[] nn = {0, 0, -1, 1};
public List<String> findWords(char[][] board, String[] words) {
int m = board.length, n = board[0].length;
List<String> ans = new ArrayList<>();
for (String word : words) {
if (word.length() > m * n) continue;
boolean[][] isUsed = new boolean[m][n];
boolean flag = false;
for (int i = 0; i < m; i ++) {
if (flag) {
break;
}
for (int j = 0; j < n; j ++) {
if (findWordsCore(board, word, isUsed, 0, i, j)) {
ans.add(word);
flag = true;
break;
}
}
}
}
return ans;
}
private boolean findWordsCore(char[][] board, String word, boolean[][] isUsed, int curIndex, int m, int n) {
if (curIndex >= word.length()) {
return true;
}
if (m < 0 || m >= board.length || n < 0 || n >= board[0].length || isUsed[m][n]
|| word.charAt(curIndex) != board[m][n]) {
return false;
}
isUsed[m][n] = true;
for (int i = 0; i < 4; i ++) {
int newM = m + nm[i], newN = n + nn[i];
if (findWordsCore(board, word, isUsed, curIndex + 1, newM, newN)) {
return true;
}
}
isUsed[m][n] = false;
return false;
}
思路二:字典树
修改一下思路:由每个单词去循环遍历矩阵,改为循环遍历矩阵时找是否有匹配的单词 ;
单词的保存用字典树,字典树里的节点里也保存一下完整单词val。
找到单词后,将字典树中表示单词的isEnd置为false,防止多次遍历到,重复添加
int[] nm = {-1, 1, 0, 0};
int[] nn = {0, 0, -1, 1};
public List<String> findWords(char[][] board, String[] words) {
int m = board.length, n = board[0].length;
List<String> ans = new ArrayList<>();
TrieTree trieTree = new TrieTree();
for (String word : words) {
trieTree.insert(word);
}
boolean[][] isUsed = new boolean[m][n];
for (int i = 0; i < m; i ++) {
for (int j = 0; j < n; j ++) {
findWordsCore(board, isUsed, i, j, trieTree.root, ans);
}
}
return ans;
}
private void findWordsCore(char[][] board, boolean[][] isUsed, int m, int n, TrieNode node, List<String> ans) {
if (m < 0 || m >= board.length || n < 0 || n >= board[0].length || isUsed[m][n]) {
return;
}
char c = board[m][n];
if (node.nodes[c-'a'] == null) {
return;
}
node = node.nodes[c-'a'];
if (node.isEnd) {
ans.add(node.val);
node.isEnd = false;
}
isUsed[m][n] = true;
for (int i = 0; i < 4; i ++) {
int newM = m + nm[i], newN = n + nn[i];
findWordsCore(board, isUsed, newM, newN, node, ans);
}
isUsed[m][n] = false;
}
class TrieNode {
String val;
boolean isEnd;
TrieNode[] nodes;
TrieNode() {
nodes = new TrieNode[26];
}
}
class TrieTree {
TrieNode root = new TrieNode();
public void insert(String word) {
if (word == null || word.length() == 0) {
return;
}
TrieNode node = root;
for (int i = 0; i < word.length(); i ++) {
char c = word.charAt(i);
if (node.nodes[c-'a'] == null) {
node.nodes[c-'a'] = new TrieNode();
}
node = node.nodes[c-'a'];
}
node.isEnd = true;
node.val = word;
}
}