[Leetcode] 212. Word Search II 解题报告

本文介绍了一个二维板上寻找字典中所有单词的问题解决方案。利用前缀树(Trie)进行剪枝,并采用特殊字符标记访问过的节点,实现了高效的深度优先搜索(DFS)算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

Given a 2D board and a list of words from the dictionary, find all words in the board.

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

For example,
Given words = ["oath","pea","eat","rain"] and board =

[
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]
Return ["eat","oath"].

Note:
You may assume that all inputs are consist of lowercase letters a-z.

思路

如果这道题目的输入只是一个单词,那么设计一个DFS就可以通过。但是由于给出了一组单词,所以简单的DFS被证明无法通过大数据。因此,我们需要想办法对DFS进行剪枝,并对实现进行优化。这里给出两种优化方法:

1)采用前缀树(Trie)进行剪枝。就是首先将要搜索的所有单词都添加到字典树中,然后从地图board中的每一个元素进行开始搜索,如果往上下左右搜索的时候其元素可以在前缀树中找到,那么继续搜索(或者在搜索到某个结点的时候发现已经到了某个结点的末尾,那么就将该单词添加到结果集合中);否则就结束当前分支的搜索。

2)采用特殊字符标记访问过的结点。一般情况下,我们可以另外开辟一个二维数组来标记已经访问过的结点。这里我们可以改变原数组的值,搜索完成之后再改回来。这种方法不仅节省空间,而且运行中速度也更快。

经过这两种方法的优化,我们的DFS算法就可以顺利通过所有测试数据。

代码

class Solution {
public:
    vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
        if (board.size() == 0 || board[0].size() == 0) {
            return {};
        }
        Trie *root = new Trie(), *node = NULL;          // Add each word to the Trie
        for (auto str : words) {
            node = root;
            for (auto ch : str) {
                if (!node->child[ch - 'a']) {
                    node->child[ch - 'a'] = new Trie();
                }
                node = node->child[ch - 'a'];
            }
            node->isWord = true;
        }
        for (int i = 0; i < board.size(); ++i) {        // Apply DFS
            for (int j = 0; j < board[0].size(); ++j) {
                DFS(board, root->child[board[i][j] - 'a'], i, j, "");
            }
        }
        return ret;
    }
private:
    struct Trie {
        vector<Trie*> child;
        bool isWord;
        Trie() : child(vector<Trie*>(26, NULL)), isWord(false){}
    };
    
    void DFS(vector<vector<char>> &board, Trie *root, int x, int y, string str) {
        int row_num = board.size(), col_num = board[0].size();
        if (!root || board[x][y] == '#') {
            return;
        }
        str += board[x][y];
        if (root->isWord) {
            ret.push_back(str);
            root->isWord = false;       // Important: delte this word
        }
        char ch = board[x][y];          // Backup board[x][y] for efficiency
        board[x][y] = '#';
        if(x + 1 < row_num) {
            DFS(board, root->child[board[x+1][y]-'a'], x+1, y, str);
        }
        if(x - 1 >= 0) {
            DFS(board, root->child[board[x-1][y]-'a'], x-1, y, str);  
        }
        if(y + 1 < col_num) {
            DFS(board, root->child[board[x][y+1]-'a'], x, y+1, str);
        }
        if(y - 1 >= 0) {
            DFS(board, root->child[board[x][y-1]-'a'], x, y-1, str);
        }
        board[x][y] = ch;  
    }
    vector<string> ret;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值