词搜索与Trie树

Posted by SkyHigh on September 27, 2016

词搜索与Trie树

Trie树

Trie树是一种比较简单的字典树,它通过前缀来构造单词的路径。当搜索一个单词的时候可以从根节点出发,一直找到单词节点(可以使用一个变量来标定)。如果该单词能够找到单词节点,那么说明这个词在字典里,否则不在(单词未搜索完或者搜索完但是未达到单词节点)。

如果字典里的字都是由小写字母构成(26个),那么可以使用如下数据结构:

struct TreeNode{
        bool isword;
        string word;
        TreeNode* next[26];
        TreeNode(){
            isword = false;
        }
    }

其中,每个变量的含义如下:

  • isword:判定是否为一个单词节点(即单词搜索到此处是否可以形成一个单词);
  • word:如果是一个单词节点,则把该单词存入到word里;
  • next:表示下一个字母,共26种可能,’a’到’z’.

词搜索

给定一个单词,如何在一个字母矩阵中找到这个单词?

如果仅仅是要判定这个单词是否在字母矩阵中,那么仅使用dfs即可。时间复杂度为O(N^2)。

如果额外给定了字典,查找所有字母矩阵中出现过的字典里的词,那么需要对字典建立Trie树,然后使用dfs搜索即可。时间复杂度为O(logN*N^2)。

词搜索I

给出一个二维的字母板和一个单词,寻找字母板网格中是否存在这个单词。

单词可以由按顺序的相邻单元的字母组成,其中相邻单元指的是水平或者垂直方向相邻。每个单元中的字母最多只能使用一次。


给出board =

[

  "ABCE",

  "SFCS",

  "ADEE"

]

word = "ABCCED", ->返回 true,

word = "SEE",-> 返回 true,

word = "ABCB", -> 返回 false.

我的代码如下:

class Solution {
public:
    /**
     * @param board: A list of lists of character
     * @param word: A string
     * @return: A boolean
     */
    bool exist(vector<vector<char> > &board, string word) {
        // write your code here
        int n = board.size();
        if(word.empty())
            return true;
        if(n<1)
            return false;
        int m = board[0].size();
        vector<vector<bool>> isvisit(n, vector<bool>(m, false));
        for(int i=0;i<board.size();i++){
            for(int j=0;j<board[0].size();j++){
                if(board[i][j]!=word[0])
                    continue;
                if(dfs(board, isvisit, word, 0, i, j))
                    return true;
            }
        }
        return false;
    }
    bool dfs(vector<vector<char>>& board, vector<vector<bool>>& isvisit, string& word, int k, int i, int j){
        if(k==word.size()-1&&word[k]==board[i][j])
            return true;
        isvisit[i][j] = true;
        if(word[k]==board[i][j]){
            // cout<<word[k]<<endl;
            if(i>0&&!isvisit[i-1][j])
                if(dfs(board, isvisit, word, k+1, i-1, j))
                    return true;
            if(i<board.size()-1&&!isvisit[i+1][j])
                if(dfs(board, isvisit, word, k+1, i+1, j))
                    return true;
            if(j>0&&!isvisit[i][j-1])
                if(dfs(board, isvisit, word, k+1, i, j-1))
                    return true;
            if(j<board[0].size()-1&&!isvisit[i][j+1])
                if(dfs(board, isvisit, word, k+1, i, j+1))
                    return true;
        }
        isvisit[i][j] = false;
        return false;
    }
};

词搜索II

给出一个由小写字母组成的矩阵和一个字典。找出所有同时在字典和矩阵中出现的单词。一个单词可以从矩阵中的任意位置开始,可以向左/右/上/下四个相邻方向移动。
样例
给出矩阵:
doaf
agai
dcan
和字典:
{"dog", "dad", "dgdg", "can", "again"}

返回 {"dog", "dad", "can", "again"}

dog:
doaf
agai
dcan
dad:
doaf
agai
dcan
can:
doaf
agai
dcan
again:
doaf
agai
dcan

我的代码如下:

class Solution {
public:
    /**
     * @param board: A list of lists of character
     * @param words: A list of string
     * @return: A list of string
     */
    struct TreeNode{
        bool isword;
        bool isfind;	# 这个是另外加的,用来标注该单词是否被搜索过,防止结果有重复
        string word;
        TreeNode* next[26];
        TreeNode(){
            isword = false;
            isfind = false;
        }
    } *root;
    vector<string> wordSearchII(vector<vector<char> > &board, vector<string> &words) {
        // write your code here
        root = new TreeNode();
        for(auto word:words)
            buildTrie(word, root);
        vector<string> res;
        vector<vector<bool>> isvisit(board.size(), vector<bool>(board[0].size(), false));
        for(int i=0;i<board.size();i++)
            for(int j=0;j<board[0].size();j++)
                dfs(board, i, j, root, res, isvisit);
        return res;
    }
    # 构造Trie树
    void buildTrie(string& word, TreeNode* r){
        for(auto c:word){
            if(!r->next[c-'a'])
                r->next[c-'a'] = new TreeNode();
            r = r->next[c-'a'];
        }
        r->isword = true;
        r->word = word;
    }
    void dfs(vector<vector<char>>& board, int i, int j, TreeNode* r, vector<string>& res, vector<vector<bool>>& isvisit){
        char c = board[i][j];
        isvisit[i][j] = true;
        // cout<<c<<endl;
        if(r->next[c-'a']){
            r = r->next[c-'a'];
            if(r->isword&&!r->isfind){
                res.push_back(r->word);
                r->isfind=true;
            }
            if(i>0&&!isvisit[i-1][j])
                dfs(board, i-1, j, r, res, isvisit);
            if(i<board.size()-1&&!isvisit[i+1][j])
                dfs(board, i+1, j, r, res, isvisit);
            if(j>0&&!isvisit[i][j-1])
                dfs(board, i, j-1, r, res, isvisit);
            if(j<board[0].size()-1&&!isvisit[i][j+1])
                dfs(board, i, j+1, r, res, isvisit);
        }
        isvisit[i][j] = false;
    }
};