[NeetCode 150] Search for Word II

Given a 2-D grid of characters board and a list of strings words, return all words that are present in the grid.

For a word to be present it must be possible to form the word with a path in the board with horizontally or vertically neighboring cells. The same cell may not be used more than once in a word.

Example 1:

复制代码
Input:
board = [
  ["a","b","c","d"],
  ["s","a","a","t"],
  ["a","c","k","e"],
  ["a","c","d","n"]
],
words = ["bat","cat","back","backend","stack"]

Output: ["cat","back","backend"]

Example 2:

复制代码
Input:
board = [
  ["x","o"],
  ["x","o"]
],
words = ["xoxo"]

Output: []

Constraints:

复制代码
1 <= board.length, board[i].length <= 10
board[i] consists only of lowercase English letter.
1 <= words.length <= 100
1 <= words[i].length <= 10

words[i] consists only of lowercase English letters.

All strings within words are distinct.

Solution

Compared with basic Search for Word, this problem involves multiple queries. For one query, we have to go through the whole matrix and apply DFS, which consume O ( n × m × Len ( w o r d ) ) O(n\times m\times \text{Len}(word)) O(n×m×Len(word)) time complexity. If we simply repeat this process on every query, the time complexity is O ( n × m × ∑ w ∈ w o r d s Len ( w ) ) O(n\times m\times \sum_{w\in words}\text{Len}(w)) O(n×m×∑w∈wordsLen(w)), which is too time-consuming.

In fact, we can go through the whole matrix and apply DFS at each position only once, because in just one going through, we can meet all possible words that can be produced by the matrix. There is no need to repeat it.

One possible solution is to record all strings while we go through the matrix, using a set or hash algorithm, but the number of all possible strings might be large and we only need few among them. The overall time and space complexity will be O ( n 2 m 2 ) O(n^2m^2) O(n2m2).

Actually, the DFS can be much more efficient if we search according to the given word list. To achieve this, we can build a Trie tree on all the words we want to find in the matrix. Then, we simultaneously move on both the matrix and Trie tree. Under the guidance of Trie tree, we only search the position that can compose a prefix of target words. Although in the worst case, the time complexity will still be O ( n 2 m 2 ) O(n^2m^2) O(n2m2), but in general cases, the time complexity will be about O ( ∑ w ∈ w o r d s Len ( w ) ) O( \sum_{w\in words}\text{Len}(w)) O(∑w∈wordsLen(w)) and the space complexity will be constantly O ( n × m + ∑ w ∈ w o r d s Len ( w ) ) O(n\times m+ \sum_{w\in words}\text{Len}(w)) O(n×m+∑w∈wordsLen(w)).

Code

py 复制代码
class Trie:
    def __init__(self):
        self.is_word = [False]
        self.tree = [{}]
        self.id_cnt = 0
        self.word_cnt = [0]
    
    def insert(self, word):
        node = 0
        self.word_cnt[0] += 1
        for c in word:
            if c not in self.tree[node]:
                self.id_cnt += 1
                self.tree[node][c] = self.id_cnt
                self.is_word.append(False)
                self.tree.append({})
                self.word_cnt.append(0)
            node = self.tree[node][c]
            self.word_cnt[node] += 1
        self.is_word[node] = True

    def remove(self, word):
        node = 0
        self.word_cnt[0] -= 1
        for c in word:
            if c not in self.tree[node]:
                return
            node = self.tree[node][c]
            if self.word_cnt[node] <= 0:
                return
            self.word_cnt[node] -= 1
        self.is_word[node] = False



class Solution:
    def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
        trie = Trie()
        for word in words:
            trie.insert(word)
        ans = []
        vis = set()
        X = [ 1,-1, 0, 0]
        Y = [ 0, 0, 1,-1]
        def dfs(x, y, node, string):
            print(x, y, node, string)
            if trie.word_cnt[node] <= 0:
                return
            if trie.is_word[node]:
                ans.append(string)
                trie.remove(string)
            vis.add((x, y))
            for i in range(4):
                nxt_x = x + X[i]
                nxt_y = y + Y[i]
                if 0 <= nxt_x < len(board) and 0 <= nxt_y < len(board[0]) and (nxt_x, nxt_y) not in vis:
                    nxt_char = board[nxt_x][nxt_y]
                    if nxt_char in trie.tree[node]:
                        dfs(nxt_x, nxt_y, trie.tree[node][nxt_char], string+nxt_char)
            vis.remove((x,y))
            return False

        for i in range(len(board)):
            for j in range(len(board[0])):
                if board[i][j] in trie.tree[0]:
                    dfs(i, j, trie.tree[0][board[i][j]], board[i][j])
        return ans
        
相关推荐
RFdragon43 分钟前
分享本周所学——三维重建算法3D Gaussian Splatting(3DGS)
人工智能·线性代数·算法·机器学习·计算机视觉·矩阵·paddlepaddle
Zero6 小时前
机器学习微积分--(1)核心思想
人工智能·算法·机器学习
有Li7 小时前
一种病理学内容感知变速率学习图像压缩框架 (PathoLIC)/文献速递-多模态应用技术
人工智能·深度学习·算法·计算机视觉·医学生
x_xbx7 小时前
LeetCode:34. 在排序数组中查找元素的第一个和最后一个位置
数据结构·算法·leetcode
Ricky_Theseus7 小时前
数据库关系代数 - 连接操作
linux·数据库·算法
绿算技术7 小时前
宝辰股份董事长莅临绿算技术调研交流
人工智能·科技·算法
码云数智-园园7 小时前
哈希冲突的解决之道:深入理解哈希表底层原理
算法·哈希算法
qq_416018727 小时前
C++中的模板方法模式
开发语言·c++·算法
天上路人8 小时前
A-59F 多功能语音处理模组在本地会议系统扩音啸叫处理中的技术应用与性能分析
人工智能·神经网络·算法·硬件架构·音视频·语音识别·实时音视频
yang_B6219 小时前
噪声处理方法
大数据·人工智能·算法