[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
        
相关推荐
lizz3114 分钟前
机器学习中的线性代数:奇异值分解 SVD
线性代数·算法·机器学习
MSTcheng.19 分钟前
【C语言】动态内存管理
c语言·开发语言·算法
不去幼儿园23 分钟前
【启发式算法】Dijkstra算法详细介绍(Python)
人工智能·python·算法·机器学习·启发式算法·图搜索算法
serve the people31 分钟前
神经网络中梯度计算求和公式求导问题
神经网络·算法·机器学习
闻缺陷则喜何志丹37 分钟前
【二分查找、滑动窗口】P10389 [蓝桥杯 2024 省 A] 成绩统计|普及+
c++·算法·蓝桥杯·二分查找·滑动窗口·洛谷·成绩
乔冠宇2 小时前
蓝桥杯算法——铠甲合体
算法·职场和发展·蓝桥杯
商bol452 小时前
算阶,jdk和idea的安装
数据结构·c++·算法
迷迭所归处2 小时前
C语言 —— 愿文明如薪火般灿烂 - 函数递归
c语言·开发语言·算法
柠檬鲨_5 小时前
C语言100天练习题【记录本】
c语言·数据结构·算法
float_六七5 小时前
二叉树三种遍历方式——前序、中序、后序(C++)
开发语言·c++·算法