2015-10-18 10:42:52 +08:00

142 lines
4.0 KiB
C++

// Source : https://leetcode.com/problems/word-search-ii/
// Author : Hao Chen
// Date : 2015-06-10
/**********************************************************************************
*
* Given a 2D board and a list of words from the dictionary, find all words in the board.
*
* Each word must be constructed from letters of sequentially adjacent cell, where "adjacent"
* cells are those horizontally or vertically neighboring. The same letter cell may not be used
* more than once in a word.
*
* For example,
* Given words = ["oath","pea","eat","rain"] and board =
*
* [
* ['o','a','a','n'],
* ['e','t','a','e'],
* ['i','h','k','r'],
* ['i','f','l','v']
* ]
*
* Return ["eat","oath"].
*
* Note:
* You may assume that all inputs are consist of lowercase letters a-z.
*
* click to show hint.
*
* You would need to optimize your backtracking to pass the larger test. Could you stop backtracking earlier?
*
* If the current candidate does not exist in all words' prefix, you could stop backtracking immediately.
* What kind of data structure could answer such query efficiently? Does a hash table work? Why or why not?
* How about a Trie? If you would like to learn how to implement a basic trie, please work on this problem:
* Implement Trie (Prefix Tree) first.
*
**********************************************************************************/
const int MAX_CHARS = 26;
class TrieNode {
public:
TrieNode(string s):isWord(false), word(s) {
memset(children, 0, sizeof(children));
}
TrieNode* & operator [] (char ch) {
return children[(ch - 'a') % MAX_CHARS];
}
TrieNode* & operator [] (int idx) {
return children[idx % MAX_CHARS];
}
public:
string word;
bool isWord;
private:
TrieNode* children[MAX_CHARS];
};
class TrieTree {
public:
TrieTree():root(new TrieNode("")) { }
~TrieTree() { freeTree(root); }
TrieNode* getRoot() {
return root;
}
void addWord(string& s){
TrieNode *node = root;
string t;
for (int i=0; i<s.size(); i++){
t += s[i];
if ( (*node)[s[i]] == NULL ){
(*node)[s[i]] = new TrieNode(t);
}
node = (*node)[s[i]];
}
node->isWord = true;
}
private:
void freeTree(TrieNode* node){
for(int i=0; i<MAX_CHARS; i++){
if ((*node)[i]!=NULL){
freeTree((*node)[i]);
}
}
delete node;
}
TrieNode *root;
};
class Solution {
public:
void findWords(vector<vector<char>>& board, TrieNode* root, int row, int col, vector<string>& result){
if (row < 0 || col < 0 ||
row >= board.size() ||
col >= board[row].size() ||
board[row][col] == '\0' ) {
return;
}
char ch = board[row][col];
root = (*root)[ch];
if (root==NULL) return;
if (root->isWord){
result.push_back(root->word);
root->isWord = false;
}
board[row][col] = '\0';
findWords(board, root, row, col - 1, result);
findWords(board, root, row, col + 1, result);
findWords(board, root, row + 1, col, result);
findWords(board, root, row - 1, col, result);
board[row][col] = ch;
}
public:
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
TrieTree t;
for (int i = 0; i<words.size(); i++){
t.addWord(words[i]);
}
vector<string> result;
for (int i = 0; i<board.size(); i++) {
for (int j = 0; j < board[i].size(); j++) {
findWords(board, t.getRoot(), i, j, result);
}
}
return result;
}
};