leetcode问题--单词搜索 II

leetcode问题--单词搜索 II

#前缀树–单词搜索II

问题描述

给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。

示例:

输入:
words = [“oath”,“pea”,“eat”,“rain”] and board =
[
[‘o’,‘a’,‘a’,‘n’],
[‘e’,‘t’,‘a’,‘e’],
[‘i’,‘h’,‘k’,‘r’],
[‘i’,‘f’,‘l’,‘v’]
]
输出: [“eat”,“oath”]
说明:
你可以假设所有输入都由小写字母 a-z 组成。

提示:
1、你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
2、如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?

问题分析

我一开始没有理解题意,我以为题目中“同一个单元格内的字母在一个单词中不能重复出现”的意思是:同一个字母不能出现在两个单词中。后来看了参考答案,我才发现是我想多了。题目只是要求同一个字母不能重复出现在一个单词中,但可以出现在两个单词中。同时,根据参考答案,我才理解最终输出的匹配单词中不能有重复的单词。根据这几个原则,我们就可以实现我们的代码。
首先,我们采用前缀树存储要匹配的单词,可以节省空间和搜索时间。然后以每一个字母为中心,向上下左右分别搜索,如果匹配到了单词,就返回并存储下来;如果不匹配就不停止搜索。同时每当匹配到一个单词或节点没有子节点时,就对前缀树实现剪枝,从而极大优化算法复杂度。

具体代码

`代码一共分为两部分,第一部分construct()是构造前缀树的函数,后一部分findWords()就是对每一个字母进行搜索来匹配单词。

class Solution:
    def __init__(self):
        self.lookup = {}
        self.word_matched = []
    def construct(self, words):
        for word in words:
            tree = self.lookup
            for a in word:
                if a not in tree:
                    tree[a] = {}
                tree = tree[a]
            tree['#'] = word

    def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
        self.construct(words)
        #以board中的每一个字母为中心,进行上下左右遍历,如果不存在单词或找到单词就停止回溯
        for i in range(len(board)):
            for j in range(len(board[0])):
                if board[i][j] in self.lookup:
                    self.recall(board, i, j, self.lookup)
        return self.word_matched
    
    def recall(self, board, i, j, parent): 
        letter = board[i][j]
        tree = parent[letter]
        if '#' in tree:
            self.word_matched.append(tree.pop('#', False))
        #将每一个被遍历过的节点都标记一下,防止重复遍历
        board[i][j] = '$'
        #对board[i][j]的上下左右进行遍历
        for (rowOffset, colOffset) in [(-1, 0), (0, 1), (1, 0), (0, -1)]:
            newi, newj = i + rowOffset, j + colOffset
            if newi <0 or newi >= len(board) or newj < 0 or newj >= len(board[0]):
                continue
            if board[newi][newj] not in tree:
                continue
            self.recall(board, newi, newj, tree)
        if not tree:
            parent.pop(letter)
        board[i][j] = letter
        return
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值