212. 单词搜索 II (DFS Trie )
难度困难
给定一个 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"] 输出:[]
from collections import defaultdict class Trie: def __init__(self): self.children = defaultdict(Trie) self.is_end = False self.word = "" def insert(self,word): node = self for ch in word: node = node.children[ch] node.is_end = True node.word = word #print(node.word) class Solution: def __init__(self): self.res = [] def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: def dfs(board,i,j,root): if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]): return if root == None: return ch = board[i][j] if ch not in root.children: return if root.children[ch].is_end: self.res.append(root.children[ch].word) if not root.children[ch].children: return board[i][j] = "#" for ij in [[i+1,j],[i-1,j],[i,j+1],[i,j-1]]: dfs(board,ij[0],ij[1],root.children[ch]) board[i][j] = ch root = Trie() for word in words: root.insert(word) for i in range(len(board)): for j in range(len(board[0])): path = [] dfs(board,i,j,root) return list(set(self.res))
from collections import defaultdict class Trie: def __init__(self): self.children = defaultdict(Trie) self.is_end = False self.word = "" def insert(self,word): node = self for ch in word: node = node.children[ch] node.is_end = True node.word = word class Solution: def __init__(self): self.root = Trie() self.res = set() def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: def dfs(board,i,j,root): if root == None: return if i < 0 or j < 0 or i >= len(board) or j >= len(board[0]): return ch = board[i][j] if ch =='#' or ch not in root.children: return node = root.children[ch] if node.is_end: self.res.add(node.word) #剪枝,不然会超时 if not node.children: return board[i][j] = '#' for i2, j2 in [(i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1)]: dfs(board,i2,j2,node) board[i][j] = ch for word in words: self.root.insert(word) for i in range(len(board)): for j in range(len(board[0])): dfs(board,i,j,self.root) return list(self.res)
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; } };