dfs 解决(隐式)图搜索问题

132. 单词搜索 II

中文
English

给出一个由小写字母组成的矩阵和一个字典。找出所有同时在字典和矩阵中出现的单词。一个单词可以从矩阵中的任意位置开始,可以向左/右/上/下四个相邻方向移动。一个字母在一个单词中只能被使用一次。且字典中不存在重复单词

样例

样例 1:

输入:["doaf","agai","dcan"],["dog","dad","dgdg","can","again"]
输出:["again","can","dad","dog"]
解释:
  d o a f
  a g a i
  d c a n
矩阵中查找,返回 ["again","can","dad","dog"]。

样例 2:

输入:["a"],["b"]
输出:[]
解释:
 a
矩阵中查找,返回 []。

挑战

使用单词查找树来实现你的算法

 

DIRECTIONS = [(0, -1), (0, 1), (-1, 0), (1, 0)]

class Solution:
    """
    @param board: A list of lists of character
    @param words: A list of string
    @return: A list of string
    """
    def wordSearchII(self, board, words):
        if board is None or len(board) == 0:
            return []
        
        word_set = set(words)
        prefix_set = set()
        for word in words:
            for i in range(len(word)):
                prefix_set.add(word[:i + 1])
        
        result = set()
        for i in range(len(board)):
            for j in range(len(board[0])):
                c = board[i][j]
                self.search(
                    board,
                    i,
                    j,
                    board[i][j],
                    word_set,
                    prefix_set,
                    set([(i, j)]),
                    result,
                )
                
        return list(result)
        
    def search(self, board, x, y, word, word_set, prefix_set, visited, result):
        if word not in prefix_set:
            return
        
        if word in word_set:
            result.add(word)
        
        for delta_x, delta_y in DIRECTIONS:
            x_ = x + delta_x
            y_ = y + delta_y
            
            if not self.inside(board, x_, y_):
                continue
            if (x_, y_) in visited:
                continue
            
            visited.add((x_, y_))
            self.search(
                board,
                x_,
                y_,
                word + board[x_][y_],
                word_set,
                prefix_set,
                visited,
                result,
            )
            visited.remove((x_, y_))
            
    def inside(self, board, x, y):
        return 0 <= x < len(board) and 0 <= y < len(board[0])

 注意使用prefix hash map来剪枝。

使用trie的解法:

DIRECTIONS = [(0, -1), (0, 1), (-1, 0), (1, 0)]

class TrieNode:    		#定义字典树的节点
    def __init__(self):
        self.children = {}
        self.is_word = False
        self.word = None
        
        
class Trie:
    def __init__(self):
        self.root = TrieNode()
        
    def add(self, word):		#字典树插入单词
        node = self.root
        for c in word:
            if c not in node.children:
                node.children[c] = TrieNode()   #在此节点申请节点
            node = node.children[c]     		#继续遍历
        node.is_word = True
        node.word = word        #存入单词
        
    def find(self, word):	
        node = self.root
        for c in word:
            node = node.children.get(c)
            if node is None:
                return None
                
        return node
        

class Solution:
    """
    @param board: A list of lists of character
    @param words: A list of string
    @return: A list of string
    """
    def wordSearchII(self, board, words):
        if board is None or len(board) == 0:
            return []
            
        trie = Trie()
        for word in words:			#插入单词
            trie.add(word)

        result = set()
        for i in range(len(board)):				#遍历字母矩阵,将每个字母作为单词首字母开始搜索
            for j in range(len(board[0])):
                c = board[i][j]
                self.search(
                    board,
                    i,
                    j,
                    trie.root.children.get(c),
                    set([(i, j)]),
                    result,
                )
                
        return list(result)
        
    def search(self, board, x, y, node, visited, result):			#在字典树上dfs查找
        if node is None:
            return
        
        if node.is_word:
            result.add(node.word)
        
        for delta_x, delta_y in DIRECTIONS:				#向四个方向查找
            x_ = x + delta_x
            y_ = y + delta_y
            
            if not self.inside(board, x_, y_):
                continue
            if (x_, y_) in visited:
                continue
            
            visited.add((x_, y_))
            self.search(
                board,
                x_,
                y_,
                node.children.get(board[x_][y_]),
                visited,
                result,
            )
            visited.remove((x_, y_))
            
    def inside(self, board, x, y):
        return 0 <= x < len(board) and 0 <= y < len(board[0])

 

posted @ 2019-10-25 21:35  bonelee  阅读(546)  评论(0编辑  收藏  举报