Word Search II 题解

来源:互联网 发布:淘宝客新建导购推广 编辑:程序博客网 时间:2024/05/17 04:18

题目:

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.

For example,
Given words = [“oath”,”pea”,”eat”,”rain”] and board =
[
[‘o’,’a’,’a’,’n’],
[‘e’,’t’,’a’,’e’],
[‘i’,’h’,’k’,’r’],
[‘i’,’f’,’l’,’v’]
]

Return [“eat”,”oath”].

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

Difficulty: Hard

翻译:

给定一个矩阵和一系列单词,判断这些单词是否都存在于矩阵中

分析:

经过了 Word Search 题解 和 Implement Trie (Prefix Tree) 题解 两道题的铺垫,终于到了今天这道题了
leetcode上hard难度的题都各有特点,很多是一个系列中加强某个限制条件让同样的问题上升一个难度,而往往直接套用上一个题的思路是行不通的,这道题就是如此,乍一看理论上用Word Search架子的代码外面套一层循环是可行的,但是,在大量单词集合的情况下必然会超时,所以我们就要想个办法,如何减少单词的比较次数?
结合英语单词的特点我们很快就会想出一个思路,英语单词大量使用词根词缀,很大部分是重复的,我们完全可以利用这一个性质来缩小查找单词的次数
好了,思路有了,我们就看看怎么实现,本科期间我在信息检索课后自己写过一个论文检索引擎,恰巧就是这个思想,当时的实现是用链式哈希建立多级索引,实现同样前缀的分类,后来发现我好蠢,前人已经有更好的树结构来解决这个问题,就是—–字典树,关于字典树的一切请看我的博客Implement Trie (Prefix Tree) 题解
好了,废话不多说,直接上代码:

代码

//字典树定义#define MAX 26class TrieNode {public:    TrieNode *next[MAX];    bool isWord;    TrieNode() :isWord(false) {        memset(next, NULL, sizeof(next));    }};//字典树功能class TrieFunc {    TrieNode *root;public:    TrieFunc() {        root = new TrieNode();    }    TrieNode *GetRoot() {        return root;    }    void insert(string word) {        TrieNode *p = root;        for (auto &a : word) {            if (!p->next[a - 'a'])                p->next[a - 'a'] = new TrieNode();            p = p->next[a - 'a'];        }        p->isWord = true;    }};class Solution {    vector<string> ret;public:     //判断部分    void searchWord(vector<vector<char>>& board, string curr,TrieNode *root,int i,int j) {        int m = board.size();        int n = board[0].size();        if (i < 0 || i >= m || j < 0 || j >= n || !root||board[i][j] == '\0') return ;        if (!root->next[board[i][j] - 'a']) return ;        root = root->next[board[i][j] - 'a'];        char temp = board[i][j];        board[i][j] = '\0';        curr.push_back(temp);        if (root->isWord) {            root->isWord = false;            ret.push_back(curr);        }        searchWord(board, curr, root, i + 1, j);        searchWord(board, curr, root, i - 1, j);        searchWord(board, curr, root, i, j + 1);        searchWord(board, curr, root, i, j - 1);        board[i][j] = temp;        curr.pop_back();    }    //主函数    vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {        string curr;        if (board.empty()) return ret;        TrieFunc trie;        //将单词全部插入字典树        for (auto &a : words) {            trie.insert(a);        }        //对字典树进行查询        TrieNode *root = trie.GetRoot();        for (int i = 0; i < board.size(); i++)            for (int j = 0; j < board[0].size(); j++) {                searchWord(board, curr, root, i, j);            }        return ret;    }};

代码比较长,容易乱的几个地方需要说明:
1、字典树存的是待存单词,不是矩阵可能构成的单词
2、查询函数查询的是字典树,也就是存在字典树后原单词集合不再使用
3、bool isWord 变量是标志字典树中的路径是否是一个单词,也即是说,isWord 就是字典树中找单词的判定条件
4、if (i < 0 || i >= m || j < 0 || j >= n || !root||board[i][j] == '\0') return ; 这句中的board[i][j] == '\0' 这个条件不能省,Word Search题中是没有这个条件的,因为一个字符匹配判断是针对原单词,本题是针对字典树

0 0
原创粉丝点击