[leetcode]212. Word Search II

本文介绍LeetCode上单词搜索II的问题解决方法,通过构建字典树(Trie)来高效查找给定二维字符网格中出现的所有字典词汇。采用深度优先搜索(DFS)策略遍历网格并匹配字典树中的路径。

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

链接:https://leetcode.com/problems/word-search-ii/description/

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.

Example:

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

Output: ["eat","oath"]


class Solution {
public:

    struct TrieNode {
        string word;
        unordered_map<char,TrieNode *> children;
        TrieNode() {
            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;
    }
    int dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

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

        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);
            }
        }        
       
        return res;        
    }
};

利用字典树Trie来做, 就是将要搜索的单词先添加到字典树中, 然后从地图board的每一个元素搜索, 如果往上下左右搜索的时候其元素可以在字典树中找到, 那么就继续搜索下去, 并且如果搜索到某个结点的时候发现到这个结点构成了一个单词, 那么就将单词添加到结果集合中. 如果在字典树中无法找到这个元素, 那么就结束当前分支的搜索.

另外还需要标记搜索过的点, 可以再开一个二维数组来标记, 也可以改变其值, 搜索完之后再改回来, 这种方法的好处是不用额外的空间, 速度也会更快.

class Solution {
public:
    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=board.size(),col=board[0].size();
        if(!root || board[x][y]=='#') return;
        
        str+=board[x][y];
        if(root->isWord)
        {
            ans.push_back(str);
            root->isWord=false;
        }
        
        char ch=board[x][y];
        board[x][y]='#';
        
        if(x+1<row) 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) 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> findWords(vector<vector<char>>& board, vector<string>& words) {
        if(board.size()==0) return {};
        Trie* root=new Trie(),*node;
        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++)
        {
            for(int j=0;j<board[0].size();j++)
            {
                DFS(board,root->child[board[i][j]-'a'],i,j,"");
            }
        }
        return ans;
    }
private:  
    vector<string> ans;  
};
class Solution {
public:
    vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
         if(words.size()==0)
            return {};
        int m=board.size(),n=board[0].size();
        if(!m || !n)
            return {};
        
        
        
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                for(auto _:words)
                {
                    b=board;
                    bool flag=false;
                    if (b[i][j]==_[0])
                        flag=search(i,j,b,_,0);
                    if(flag)
                        w.insert(_);
                }
                
            }
        }
        return vector<string>(w.begin(),w.end());
    }
    bool search(int i,int j,vector<vector<char>>& b,string &w,int index)
    {
        if(index==w.size())
            return true;
        if(i<0 || i==b.size() || j<0 || j==b[i].size() || b[i][j]!=w[index])
            return false;
        char t=b[i][j];
        b[i][j]='\0';
        bool down=search(i+1,j,b,w,index+1);
        bool up=search(i-1,j,b,w,index+1);
        bool right=search(i,j+1,b,w,index+1);
        bool left=search(i,j-1,b,w,index+1);
        if(up || down || left || right)
            return true;
        b[i][j]=t;
        return false;
    }
private:
    vector<vector<char>> b;
    set<string> w;
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值