LeetCode //C - 212. Word Search II

Given an m x n board of characters and a list of strings words , return all words on the board.

Each word must be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.

Example 1:

Input: board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"]
Output: ["eat","oath"]

Example 2:

Input: board = [["a","b"],["c","d"]], words = ["abcb"]
Output: []

Constraints:
  • m == board.length
  • n == board[i].length
  • 1 <= m, n <= 12
  • board[i][j] is a lowercase English letter.
  • 1 <= words.length <= 3 ∗ 1 0 4 3 * 10^4 3∗104
  • 1 <= words[i].length <= 10
  • words[i] consists of lowercase English letters.
  • All the strings of words are unique.

From: LeetCode

Link: 212. Word Search II


Solution:

Ideas:

Trie (Prefix Tree):

A Trie is a tree-like data structure that is used to store a dynamic set of strings. Tries are particularly useful for searches in dictionaries with a large number of words. Each node of the Trie represents a single character of a word, and the path from the root node to any node in the tree represents the prefix (part of a word) associated with that node.

Benefits of Trie:

  1. Provides efficient word insertions and lookups.
  2. Allows us to search for a word prefix efficiently.

DFS Backtracking:

Backtracking is a general algorithm used to find all (or some) solutions to computational problems by incrementally building candidates towards solutions and abandoning a candidate as soon as it is determined that it cannot be extended to a valid solution.

In the context of this problem, we use backtracking to traverse the board starting from each cell. For each cell, we explore in all four possible directions (up, down, left, right) to see if we can form a word present in the Trie.

Solution Steps:

  1. Building the Trie:
  • All the words in the words array are inserted into a Trie.
  • Each node in the Trie has 26 pointers (for each lowercase English letter) and a word pointer which points to the word if that node marks the end of a valid word.
  1. DFS Search on Board:
  • We iterate over each cell of the board.
  • Starting from each cell, we perform a DFS search to build words and check if they are in the Trie.
  • While traversing, if the current sequence of characters doesn't match any prefix in the Trie, we backtrack (return from the recursion).
  • If we find a valid word (by reaching a Trie node that has a non-null word pointer), we add that word to the results.
  1. Optimization:
  • Once a word is found, we nullify the word pointer in the Trie node to ensure that the same word is not added multiple times.
Code:
c 复制代码
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

typedef struct TrieNode {
    struct TrieNode *children[26];
    char *word;
} TrieNode;

TrieNode* createNode() {
    TrieNode *node = malloc(sizeof(TrieNode));
    for (int i = 0; i < 26; i++) {
        node->children[i] = NULL;
    }
    node->word = NULL;
    return node;
}

void insert(TrieNode *root, char *word) {
    TrieNode *node = root;
    for (int i = 0; word[i]; i++) {
        int index = word[i] - 'a';
        if (!node->children[index]) {
            node->children[index] = createNode();
        }
        node = node->children[index];
    }
    node->word = word;
}

void backtrack(char **board, int boardSize, int* boardColSize, TrieNode *node, int i, int j, char **result, int *returnSize) {
    if (i < 0 || i >= boardSize || j < 0 || j >= boardColSize[i] || board[i][j] == '#') {
        return;
    }
    
    char c = board[i][j];
    if (!node->children[c - 'a']) {
        return;
    }

    node = node->children[c - 'a'];
    if (node->word) {
        result[*returnSize] = node->word;
        (*returnSize)++;
        node->word = NULL; // To avoid duplication
    }

    board[i][j] = '#';  // Mark as visited
    backtrack(board, boardSize, boardColSize, node, i+1, j, result, returnSize);
    backtrack(board, boardSize, boardColSize, node, i-1, j, result, returnSize);
    backtrack(board, boardSize, boardColSize, node, i, j+1, result, returnSize);
    backtrack(board, boardSize, boardColSize, node, i, j-1, result, returnSize);
    board[i][j] = c;    // Revert back
}

char** findWords(char** board, int boardSize, int* boardColSize, char **words, int wordsSize, int* returnSize) {
    TrieNode *root = createNode();
    for (int i = 0; i < wordsSize; i++) {
        insert(root, words[i]);
    }
    
    char **result = malloc(wordsSize * sizeof(char*));
    *returnSize = 0;

    for (int i = 0; i < boardSize; i++) {
        for (int j = 0; j < boardColSize[i]; j++) {
            backtrack(board, boardSize, boardColSize, root, i, j, result, returnSize);
        }
    }

    return result;
}
相关推荐
凡人叶枫1 小时前
C++中智能指针详解(Linux实战版)| 彻底解决内存泄漏,新手也能吃透
java·linux·c语言·开发语言·c++·嵌入式开发
power 雀儿1 小时前
掩码(Mask)机制 结合 多头自注意力函数
算法
会叫的恐龙1 小时前
C++ 核心知识点汇总(第六日)(字符串)
c++·算法·字符串
小糯米6011 小时前
C++顺序表和vector
开发语言·c++·算法
We་ct1 小时前
LeetCode 56. 合并区间:区间重叠问题的核心解法与代码解析
前端·算法·leetcode·typescript
Lionel6892 小时前
分步实现 Flutter 鸿蒙轮播图核心功能(搜索框 + 指示灯)
算法·图搜索算法
小妖6662 小时前
js 实现快速排序算法
数据结构·算法·排序算法
xsyaaaan2 小时前
代码随想录Day30动态规划:背包问题二维_背包问题一维_416分割等和子集
算法·动态规划
凡人叶枫3 小时前
C++中输入、输出和文件操作详解(Linux实战版)| 从基础到项目落地,避坑指南
linux·服务器·c语言·开发语言·c++
zheyutao3 小时前
字符串哈希
算法