LeetCode-212-单词搜索 II

文章介绍了如何结合字典树和深度优先搜索(DFS)来高效地遍历二维网格中的字符串。首先构建字典树存储输入的单词,然后通过DFS遍历矩阵,遇到每个节点时检查其在字典树中是否存在并更新结果。同时,为了避免重复结果,使用了集合对结果进行去重。在第二个方法中,删除已访问的字符串以进一步优化性能。
摘要由CSDN通过智能技术生成

在这里插入图片描述

1、字典树+DFS

我们可以使用 DFS 来遍历整个二维网格构成的图,能否按照字符串的顺序遍历每一个节点。其中,为了避免在查询有着相同前缀的单词时花费过多时间,我们可以使用字典树进行优化。

我们首先构造字典树结构,参考字典树。我们可以使用一个字典树中的一个节点来表示字符串中的一个字符,利用哈希表来储存下一个字符与对应字典树节点之间的映射关系。当一个字符串遍历完成时,我们将该节点的word修改为对应字符串的值。因此我们可以根据一个节点的word长度来判断当前单词是否遍历完成。

在主函数中,我们先根据字符串数组构建出我们的字典树,而后我们对二维矩阵中的每一个节点都调用 DFS 搜索。在搜索过程中我们首先判断当前位置对应的字符在字典树中是否有对应的节点,若没有则直接返回 false 。而后我们判断当前节点是否为字符串的末尾,若是则需要将当前结果压入最终结果中。而后我们向当前位置的四个方向进行探索,当新位置合法而且尚未被访问时,我们递归调用 DFS 进行探索。递归结束之后将当前位置恢复原来的字符以免干扰其他位置开始的探索。

值得注意的是,考虑到一个字符串在二维矩阵中可能有不止一种的遍历方法,因此我们使用set对初始结果进行筛选,而后将集合中的结果统一返回。

struct TrieNode {
    string word;
    unordered_map<char,TrieNode *> children;
    TrieNode() {
        this->word = "";
    }   
};

void insertTrie(TrieNode * root,const string & word) {
    TrieNode * node = root;
    for (auto c : word){
        if (!node->children.count(c)) {
            node->children[c] = new TrieNode();
        }
        node = node->children[c];
    }
    node->word = word;
}

class Solution {
public:
    int dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

    bool dfs(vector<vector<char>>& board, int x, int y, TrieNode * root, set<string> & res) {
        char ch = board[x][y];        
        if (!root->children.count(ch)) {
            return false;
        }
        root = root->children[ch];
        if (root->word.size() > 0) {
            res.insert(root->word);
        }

        board[x][y] = '#';
        for (int i = 0; i < 4; ++i) {
            int nx = x + dirs[i][0];
            int ny = y + dirs[i][1];
            if (nx >= 0 && nx < board.size() && ny >= 0 && ny < board[0].size()) {
                if (board[nx][ny] != '#') {
                    dfs(board, nx, ny, root,res);
                }
            }
        }
        board[x][y] = ch;

        return true;      
    }

    vector<string> findWords(vector<vector<char>> & board, vector<string> & words) {
        TrieNode * root = new TrieNode();
        set<string> res;
        vector<string> ans;

        for (auto & word: words){
            insertTrie(root,word);
        }
        for (int i = 0; i < board.size(); ++i) {
            for (int j = 0; j < board[0].size(); ++j) {
                dfs(board, i, j, root, res);
            }
        }        
        for (auto & word: res) {
            ans.emplace_back(word);
        }
        return ans;        
    }
};

2、删除已访问的字符串

在方法一的基础上,我们可以在对一个字符串访问完成之后,删除这个字符串对应的字典树节点,从而避免在结果中重复出现相同的字符串。

struct TrieNode {
    string word;
    unordered_map<char, TrieNode *> children;
    TrieNode() {
        this->word = "";
    }   
};

void insertTrie(TrieNode * root, const string & word) {
    TrieNode * node = root;

    for (auto c : word) {
        if (!node->children.count(c)) {
            node->children[c] = new TrieNode();
        }
        node = node->children[c];
    }

    node->word = word;
}

class Solution {
public:
    int dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

    bool dfs(vector<vector<char>>& board, int x, int y, TrieNode * root, set<string> & res) {
        char ch = board[x][y];   
     
        if (root == nullptr || !root->children.count(ch)) {
            return false;
        }

        TrieNode * nxt = root->children[ch];
        if (nxt->word.size() > 0) {
            res.insert(nxt->word);
            nxt->word = "";
        }
        if (!nxt->children.empty()) {
            board[x][y] = '#';
            for (int i = 0; i < 4; ++i) {
                int nx = x + dirs[i][0];
                int ny = y + dirs[i][1];
                if (nx >= 0 && nx < board.size() && ny >= 0 && ny < board[0].size()) {
                    if (board[nx][ny] != '#') {
                        dfs(board, nx, ny, nxt,res);
                    }
                }
            }
            board[x][y] = ch;
        }
        if (nxt->children.empty()) {
            root->children.erase(ch);
        }

        return true;      
    }

    vector<string> findWords(vector<vector<char>> & board, vector<string> & words) {
        TrieNode * root = new TrieNode();
        set<string> res;
        vector<string> ans;

        for (auto & word: words) {
            insertTrie(root,word);
        }
        for (int i = 0; i < board.size(); ++i) {
            for(int j = 0; j < board[0].size(); ++j) {
                dfs(board, i, j, root, res);
            }
        }        
        for (auto & word: res) {
            ans.emplace_back(word);
        }
        
        return ans;        
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值