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;
}
相关推荐
talenteddriver37 分钟前
java: Java8以后hashmap扩容后根据高位确定元素新位置
java·算法·哈希算法
跨境猫小妹1 小时前
2025 TikTok Shop:从内容爆发到系统化深耕的商业跃迁
大数据·人工智能·算法·产品运营·亚马逊
不穿格子的程序员1 小时前
从零开始写算法 —— 二叉树篇 1:二叉树的三种遍历(递归实现法)
算法·深度优先·二叉树遍历·fds
子夜江寒1 小时前
逻辑森林与贝叶斯算法简介
算法·机器学习
小妖6661 小时前
力扣(LeetCode)- 93. 复原 IP 地址(JavaScript)
javascript·tcp/ip·leetcode
黎雁·泠崖2 小时前
C 语言指针进阶教程:const 修饰、野指针规避与传址调用
c语言·开发语言
xu_yule2 小时前
算法基础-背包问题(01背包问题)
数据结构·c++·算法·01背包
我不是小upper2 小时前
从理论到代码:随机森林 + GBDT+LightGBM 融合建模解决回归问题
人工智能·深度学习·算法·随机森林·机器学习·回归
budingxiaomoli2 小时前
分治算法-快排
数据结构·算法
云泽8082 小时前
C++ STL 栈与队列完全指南:从容器使用到算法实现
开发语言·c++·算法