212. Word Search II

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"]

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

 

利用字典树+深度优先遍历的思想。对words中每个word,建立一颗字典树,每个单词的结尾字母上包含这个单词的所有信息。如下图:

那么在字母矩阵中找单词,就可以抽象为,遍历字母矩阵,寻找一条字典树中的路径,这个“路径”的定义,如果某个节点包含单词信息(上图中黄色部分),则认为找到一条路径,即找到一个单词。

1.遍历字母矩阵每个字母,并且从字典树的根节点开始搜索,如果字母是根节点的子树,则继续2。否则next字母。

2.如果字母节点在tree树中有单词信息,则把该单词加入返回的集合中。在矩阵中,访问字母上下左右的四个字母,如果有自己的孩子,则继续搜索下去。每次路径搜索时,都把路径中访问过的节点,设置为visited。

3.遍历结束,会把所有的单词返回。

 

 

 举例:从‘o’开始遍历字母矩阵,发现'o’ 在字典树的根节点的孩子里,寻找路径的步骤移到‘o’节点(该过程是个递归),于是继续遍历其上(无),下(e),左(无),右(a),寻找有没有哪个邻居是在‘o’的孩子里。诶!发现e在自己的孩子节点里;

然后继续从e开始寻找,上(e,但已访问过,pass),下(i),左(无),右(t)。诶!发现t在自己的孩子节点。。。直到h,发现h的节点信息里有单词,诶!加入到res里。这条路径访问就结束了。然后继续从a开始访问,寻找下一条路径。把字符矩阵访问结束后,可得到所有的单词。

 

附代码:

 

#include <map>

struct pos {
    int x;
    int y; 
    pos(int x,int y):x(x),y(y) {};
    pos():x(0),y(0) {};
};

struct treeNode
{
    string str;
    treeNode* child[26];

    treeNode()
    {
        str = "";
        for(int i = 0;i<26;i++)
            child[i] = NULL;
    }
};

struct WordTree
{
    treeNode* root;

    WordTree()
    {
        root = new treeNode();
    }    

    //这样构建字典树
    //保证相同的单词,只出现一次
    void insert(string s)
    {
        int len = s.length();
        if(len<=0) return;
        treeNode* p=root;
        for(int i=0;i<len;i++)
        {   
            char tmp = s[i];
            int index = tmp - 'a';
            if(!p->child[index]) {
                p->child[index] = new treeNode();
            }
            p = p->child[index];
        }
        p->str = s;
    }
};


void search(vector<vector<char> >& board,treeNode* p, int i,int j,vector<string>& res,vector<vector<bool>>& visited)
{
    if(!p->str.empty())
    {
        res.push_back(p->str);
        p->str.clear();
    }
    visited[i][j] = true;
    int direction[][2] = {{-1,0},{1,0},{0,-1},{0,1}};
    for (int k = 0; k < 4; k++)
    {
        int nx = i + direction[k][0];
        int ny = j + direction[k][1];

        //先判断坐标的有效性
        if(nx>=0 && nx<board.size())
        {
            if(ny>=0 && ny<board[0].size())
            {
                //存在字典树中,且本次路径中未被访问到
                if(p->child[board[nx][ny]-'a']&&!visited[nx][ny])
                {
                    search(board,p->child[board[nx][ny]-'a'],nx,ny,res,visited);
                }
            }
        }    
    }
    visited[i][j] = false;
}

class Solution {
public:
    vector<string> findWords(vector<vector<char> >& board, vector<string>& words) {
        vector<string> res;
        if (words.empty() || board.empty() || board[0].empty()){
            return res;
        }                
        WordTree tree;
        vector<vector<bool> > visited(board.size(), vector<bool>(board[0].size(), false));

        //构建字典树
        for (int i=0; i<words.size(); i++)
        {
            tree.insert(words[i]);
        }
        for (int i = 0; i < board.size(); ++i) {
            for (int j = 0; j < board[i].size(); ++j) {
                if (tree.root->child[board[i][j] - 'a']) {
                    search(board, tree.root->child[board[i][j] - 'a'], i, j, res,visited);
                }
            }
        }
        return res;
    }
};

 

 

 

 

posted @ 2019-03-18 18:28  0giant  阅读(280)  评论(1编辑  收藏  举报