Leetcode 212. Word Search II单词搜索2

给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。

示例:

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

输出: ["eat","oath"]

说明:
你可以假设所有输入都由小写字母 a-z 组成。

提示:

  • 你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
  • 如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)

 

做这道题前最好先做字典树和单词搜索1.

 

字典树+DFS。

最先想的是将搜索过程中能组成的所有单词全部存到字典树中,结果超时了。

后来一想这样的方法太笨效率太低了,而且很浪费空间,字典树存了太多没有出现过的单词。

但是如果字典树只存要我们搜索的单词,然后再去搜索它就能节约不少的性能和空间了。

其实就是将上面的方法反过来再修改一下。

 

另外还要注意的是出现重复的答案和没有搜索完全的答案。

超时:

class Trie
{
  public:
    struct TrieNode
    {
        vector<TrieNode *> children;
        TrieNode()
        {
            children = vector<TrieNode *>(26, NULL);
        }
        ~TrieNode()
        {
            for (int i = 0; i < 26; i++)
            {
                if (children[i] != NULL)
                {
                    delete children[i];
                }
            }
        }
    };
    TrieNode *root;
    Trie()
    {
        root = new TrieNode();
    }
    ~Trie()
    {
        delete root;
    }

    bool find(string word, TrieNode *&newRoot)
    {
        for (int i = 0; i < word.size(); i++)
        {
            if (newRoot->children[word[i] - 'a'] == NULL)
            {
                return false;
            }
            newRoot = newRoot->children[word[i] - 'a'];
        }
        return true;
    }

    void insert(string word)
    {
        TrieNode *newRoot = root;
        for (int i = 0; i < word.size(); i++)
        {
            if (newRoot->children[word[i] - 'a'] == NULL)
            {
                newRoot->children[word[i] - 'a'] = new TrieNode();
            }
            newRoot = newRoot->children[word[i] - 'a'];
        }
    }

    bool startsWith(string prefix)
    {
        TrieNode *newRoot = root;
        return find(prefix, newRoot);
    }
};

class Solution
{
    Trie* t;
    int dx[4] = {1, -1, 0, 0};
    int dy[4] = {0, 0, 1, -1};
    int borderRow;
    int borderCol;
    vector<string> ans;
  public:
    vector<string> findWords(vector<vector<char>> &board, vector<string> &words)
    {
        t = new Trie();
        borderRow = board.size();
        if(borderRow == 0 || words.size() == 0)
        {
            return ans;
        }
        borderCol = board[0].size();
        vector<vector<bool>> visit(borderRow, vector<bool>(borderCol, false));
        map<string, bool> check;
        string str = "";
        for (int i = 0; i < words.size(); i++)
        {
            for (int r = 0; r < borderRow; r++)
            {
                for (int c = 0; c < borderCol; c++)
                {
                    if(board[r][c] == words[i][0])
                    {
                        if(check[words[i]] == true)
                            continue;
                        if (t->startsWith(words[i]))
                        {
                            //cout << r << c << "  1" << words[i] << endl;
                            check[words[i]] = true;
                            ans.push_back(words[i]);
                        }
                        else
                        {
                            visit[r][c] = true;
                            if (DFS(board, visit, r, c,  str + board[r][c], words[i]))
                            {
                                //cout << r << c <<"  2" << words[i] << endl;
                                check[words[i]] = true;
                                ans.push_back(words[i]);
                            }
                            visit[r][c] = false;
                        }
                        
                    }
                }
            }
            
        }
        return ans;
    }

    bool DFS(vector<vector<char>> &board, vector<vector<bool>> &visit, int row, int col, string str, string word)
    {
        if(str.size() >= word.size())
        {
            //cout << str << endl;
            t->insert(str);
            if(str == word)
                return true;
            return false;
        }
        for (int i = 0; i < 4; i++)
        {
            int newRow = row + dx[i];
            int newCol = col + dy[i];
            if(newRow < 0 || newRow >= borderRow || newCol < 0 || newCol >= borderCol)
                continue;
            if(visit[newRow][newCol])
                continue;
            visit[newRow][newCol] = true;
            if(DFS(board, visit, newRow, newCol, str + board[newRow][newCol], word))
            {
                visit[newRow][newCol] = false;
                return true;
            }
            visit[newRow][newCol] = false;
        }
        return false;
    }
};

正确答案:

class Solution
{
  public:
    struct TrieNode
    {
        vector<TrieNode *> children;
        bool isWord;
        TrieNode()
        {
            children = vector<TrieNode *>(26, NULL);
            isWord = false;
        }
        ~TrieNode()
        {
            for (int i = 0; i < 26; i++)
            {
                if (children[i] != NULL)
                {
                    delete children[i];
                }
            }
        }
    };

    class Trie
    {
      public:
        TrieNode *root;
        Trie()
        {
            root = new TrieNode();
        }
        ~Trie()
        {
            delete root;
        }
        void insert(string word)
        {
            TrieNode *newRoot = root;
            for (int i = 0; i < word.size(); i++)
            {
                if (newRoot->children[word[i] - 'a'] == NULL)
                {
                    newRoot->children[word[i] - 'a'] = new TrieNode();
                }
                newRoot = newRoot->children[word[i] - 'a'];
            }
            newRoot->isWord = true;
        }
    };
    void DFS(vector<vector<char>> &board, vector<vector<bool>> &visit, TrieNode *newRoot, int row, int col, string str)
    {
        if (newRoot == NULL)
            return;
        if (newRoot->isWord)
        {
//标记为false,防止出现重复的答案
            newRoot->isWord = false;
            ans.push_back(str);
            //注意如果这里return的话,某些案例下会少答案,原因可想而知
        }
        for (int i = 0; i < 4; i++)
        {
            int newRow = row + dx[i];
            int newCol = col + dy[i];
            if (newRow < 0 || newRow >= borderRow || newCol < 0 || newCol >= borderCol)
                continue;
            if (visit[newRow][newCol])
                continue;
            if (newRoot->children[board[newRow][newCol] - 'a'] == NULL)
                continue;
            visit[newRow][newCol] = true;
            DFS(board, visit, newRoot->children[board[newRow][newCol] - 'a'], newRow, newCol, str + board[newRow][newCol]);
            visit[newRow][newCol] = false;
        }
    }
    vector<string> findWords(vector<vector<char>> &board, vector<string> &words)
    {
        t = new Trie();
        borderRow = board.size();
        if (borderRow == 0 || words.size() == 0)
        {
            return ans;
        }
        borderCol = board[0].size();
//标记数组,将走过了路程标记
        vector<vector<bool>> visit(borderRow, vector<bool>(borderCol, false));
        map<string, bool> check;
        string str = "";
        for(string s : words)
        {
            t->insert(s);
        }
        for (int r = 0; r < borderRow; r++)
        {
            for (int c = 0; c < borderCol; c++)
            {
                if (t ->root ->children[board[r][c] - 'a'] != NULL)
                {
                    visit[r][c] = true;
                    TrieNode *newRoot = t->root->children[board[r][c] - 'a'];
                    DFS(board, visit, newRoot, r, c, str + board[r][c]);
                    visit[r][c] = false;
                }
            }
        }
        return ans;
    }
    private:
//字典树
      Trie *t;
//DFS所用方向数组
      int dx[4] = {1, -1, 0, 0};
      int dy[4] = {0, 0, 1, -1};
//边界
      int borderRow;
      int borderCol;
//答案
      vector<string> ans;
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值