跳转至

425.单词方块 (Hard)*

题目描述*

标签*

字典树;回溯算法;

思路 & 代码*

确定一个单词就知道了下一个单词的前缀。示例的 ["ball","area","lead","lady"],如果确定了第一个为 ball,那么下一个的前缀为 a,即 area,下一个的前缀为 le,即 lead,最后一个前缀为 lad,即 lady。一个方块完成。对整个单词列表回溯即可。搜索前缀时,还需要遍历前缀的子树,找到所有的单词,为了优化这一过程,可以在字典树结点中存当前结点所在的单词,这样在搜索前缀时就可以直接对这些单词进行 dfs 即可。

构造字典树其实比较简单,总犯错就是少了 cur = root 的初始化。。。

class TrieNode {
public:
    vector<int> idx;
    vector<TrieNode*> next;
    TrieNode() : next(26, nullptr) {}
};
class Solution {
private:
    TrieNode* root;
public:
    void buildTrie(vector<string>& words) {
        root = new TrieNode();
        auto cur = root;
        int len = words.size();
        // 构造字典树
        for(int i = 0; i < len; i++) {
            cur = root;
            for(auto& c : words[i]) {
                if(cur->next[c - 'a'] == nullptr) {
                    cur->next[c - 'a'] = new TrieNode();
                }
                cur = cur->next[c - 'a'];
                cur->idx.push_back(i);
            }
        }
    }
    vector<vector<string>> wordSquares(vector<string>& words) {
        vector<vector<string>> res;
        int len = words[0].length();
        buildTrie(words);
        vector<string> tmp(len);
        for(auto& word : words) {
            tmp[0] = word;
            dfs(res, words, tmp, len, 1);
        }
        return res;
    }
    void dfs(vector<vector<string>>& res, vector<string>& words, vector<string>& tmp, int len, int prefixLen) {
        if(prefixLen >= len) {
            res.push_back(tmp);
            return;
        }
        string prefix(prefixLen, ' ');
        // 画个图就知道前缀该取哪块了
        for(int i = 0; i < prefixLen; i++) {
            prefix[i] = tmp[i][prefixLen];
        }
        auto cur = root;
        for(auto& c : prefix) {
            if(cur->next[c - 'a'] == nullptr) {
                return;
            }
            cur = cur->next[c - 'a'];
        }
        for(auto& i : cur->idx) {
            tmp[prefixLen] = words[i];
            dfs(res, words, tmp, len, prefixLen + 1);
        }
    }
};

最后更新: July 23, 2022