难度困难
给定一个 m x n
二维字符网格 board
和一个单词(字符串)列表 words
, 返回所有二维网格上的单词 。
单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
示例 1:
输入:board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"] 输出:["eat","oath"]
示例 2:
输入:board = [["a","b"],["c","d"]], words = ["abcb"] 输出:[]
struct TrieNode { bool is_end; string word; vector<TrieNode*> children; TrieNode() { this->is_end = false; this->children = vector<TrieNode*>(26); } }; class Solution { TrieNode* root = new TrieNode(); unordered_set<string> final_set; vector<vector<int>> dirs = {{0,1},{0,-1},{1,0},{-1,0}}; public: void insert(string word) { TrieNode* node = this->root; for(auto ch :word) { if (node->children[ch-'a'] == nullptr) { node->children[ch-'a'] = new TrieNode(); } node = node->children[ch-'a']; } node->is_end = true; node->word = word; } void deleteWordFromTrie(string word) { root = remove(root, word, 0); } TrieNode* remove(TrieNode* node, string key, int i) { if (node == nullptr) { return nullptr; } if (i == key.size()) { // 找到了 key 对应的 TrieNode,删除 val node->is_end = false; } else { // 递归去子树进行删除 node->children[key[i]-'a'] = remove(node->children[key[i]-'a'], key, i + 1); } // 后序位置,递归路径上的节点可能需要被清理 if (node->is_end != false) { // 如果该 TireNode 存储着 val,不需要被清理 return node; } // 检查该 TrieNode 是否还有后缀 for (int c = 0; c < 26; c++) { if (node->children[c] != nullptr) { // 只要存在一个子节点(后缀树枝),就不需要被清理 return node; } } // 既没有存储 val,也没有后缀树枝,则该节点需要被清理 return nullptr; } void dfs(vector<vector<char>>& board,vector<vector<bool>>& visited, TrieNode* node,string& path, int i, int j) { if (i < 0 || j < 0 || i >=board.size() || j >= board[0].size() || visited[i][j]) { return; } auto ch = board[i][j]; if (node == nullptr || node->children[ch-'a'] == nullptr) { return; } path+=ch; visited[i][j] = true; if (node->children[ch-'a']->is_end) { final_set.insert(path); deleteWordFromTrie(path); } for( auto dir :dirs) { int new_i = i + dir[0]; int new_j = j + dir[1]; dfs(board,visited,node->children[ch-'a'],path,new_i,new_j); } path.pop_back(); visited[i][j] = false; } vector<string> findWords(vector<vector<char>>& board, vector<string>& words) { for(auto word : words) { insert(word); } string path = ""; vector<vector<bool>> visited = vector<vector<bool>>(board.size(),vector<bool>(board[0].size(),false)); for (int i = 0; i < board.size();i++) { for (int j = 0; j < board[0].size();j++) { dfs(board,visited, root,path,i,j); } } vector<string> final_res; for(auto w : final_set) { final_res.emplace_back(w); } return final_res; } };