LeetCode212. 单词搜索 II

题目描述

给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。

示例:

输入:

words = ["oath","pea","eat","rain"] and board =
[
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]

输出: ["eat","oath"]

说明:
你可以假设所有输入都由小写字母 a-z 组成。

提示:

你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。

思路:建立字典树,然后查询

建立字典树:遍历字符串数组,将每个元素插入到TrieNode中;
插入元素之前创建字典树的数据结构,因为在本题中只需要插入操作,所以简化TrieNode;
在插入过程中每个节点存的只是一个字符,直到当前字符串的每一个字符都遍历过(放在字典树的节点上,isEnd用来标志是否为完整字符串),将最后一个节点的val设置为当前字符串(以便于查询过程中存储);
查询:
遍历二维字符数组,且新建一个Boolean的二维数组用来标志当前字符是否已访问过;
递归调用find(i,j,node)查询,因为题目规定为四联通图所以可以直接罗列出递归组;

递归中,将visited [i] [j] 置为true,表示已经访问过;
node = node.child[board[i][j] - 'a'];
如果当前字符在Trie中存在就继续递归查询当前字符在board中能到达的位置;
直到node.isEnd = true,将node.val存入set中,且返回visited的状态置为false;

如果不存在将visited[i] [j] 返回false状态,且返回上层递归;

递归终止条件为数组越界或者当前节点已经被访问过;

代码:

public class FindWords212 {

	public List<String> findWords(char[][] board, String[] words) {

		WordTrie myTrie = new WordTrie();
		TrieNode212 root = myTrie.root;
		for (String s : words) {
			myTrie.insert(s);
		}
		Set<String> result = new HashSet<>();
		int m = board.length;
		int n = board[0].length;
		boolean[][] visited = new boolean[m][n];
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				find(board, visited, i, j, m, n, result, root);
			}
		}
		System.out.println(result);
		return new LinkedList<String>(result);
	}

	private void find(char[][] board, boolean[][] visited, int i, int j, int m, int n, Set<String> result,
			TrieNode212 node) {

		if (i < 0 || i >= m || j < 0 || j >= n || visited[i][j]) {
			return;
		}
		node = node.child[board[i][j] - 'a'];
		visited[i][j] = true;
		if (node == null) {
			visited[i][j] = false;
			return;
		}
		if (node.isEnd) {
			result.add(node.val);
		}
		find(board, visited, i + 1, j, m, n, result, node);
		find(board, visited, i, j + 1, m, n, result, node);
		find(board, visited, i, j - 1, m, n, result, node);
		find(board, visited, i - 1, j, m, n, result, node);

		visited[i][j] = false;

	}
}

class WordTrie {
	public TrieNode212 root = new TrieNode212();

	public void insert(String word) {
		TrieNode212 node = root;
		for (char ch : word.toCharArray()) {
			if (node.child[ch - 'a'] == null) {
				node.child[ch - 'a'] = new TrieNode212();
				node = node.child[ch - 'a'];
			} else {
				node = node.child[ch - 'a'];
			}
		}
		node.isEnd = true;
		node.val = word;
	}
}

class TrieNode212 {

	public String val;
	public TrieNode212[] child = new TrieNode212[26];
	public boolean isEnd = false;

	public TrieNode212() {

	}

}

你可能感兴趣的:(LeetCode,java)