// improvement: // 1) convert unordered_map to 26 bitmap (done) // 2) for each step in dfs, we don't have search the word from beginning in trie, // we can actually search from previous node. should be faster. class Node { public: char v; bool isWord; vector<Node*> m; //unordered_map<char, Node*> m; Node(char _v, bool _isWord = false) { v = _v; isWord = _isWord; m = vector<Node*>(26, nullptr); } }; class Trie { public: Node *root = new Node(0); void build(vector<string>& words) { for (auto& w : words) add(w); } void add(const string& w) { Node *cur = root; for (auto c : w) { if (cur->m[c-'a'] == nullptr) cur->m[c-'a'] = new Node(c); cur = cur->m[c-'a']; } cur->isWord = true; } int search(string &w) { Node *cur = root; for (auto c : w) { if (cur->m[c-'a'] == nullptr) return 0; cur = cur->m[c-'a']; } return cur->isWord ? 2 : 1; } }; class Solution { public: int m, n; unordered_set<string> res; string path; Trie trie; vector<string> findWords(vector<vector<char>>& board, vector<string>& words) { m = board.size(); if (m == 0) return vector<string>(); n = board[0].size(); if (n == 0) return vector<string>(); trie.build(words); for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) { path.push_back(board[i][j]); dfs(board, i, j); path.pop_back(); } return vector<string>(res.begin(), res.end()); } void dfs(vector<vector<char>>& board, int i, int j) { static int dirs[] = { -1, 0, 1, 0, -1}; int state = trie.search(path); if (state == 2) res.insert(path); else if (state == 0) return; char saved = board[i][j]; board[i][j] = ' '; for (int k = 0; k < 4; k++) { int ni = i + dirs[k]; int nj = j + dirs[k+1]; if (ni < 0 || ni >= m || nj < 0 || nj >= n || board[ni][nj] == ' ') continue; path.push_back(board[ni][nj]); dfs(board, ni, nj); path.pop_back(); } board[i][j] = saved; } };