LC 425. Word Squares

Given a set of words (without duplicates), find all word squares you can build from them.

A sequence of words forms a valid word square if the kth row and column read the exact same string, where 0 ≤ k < max(numRows, numColumns).

For example, the word sequence ["ball","area","lead","lady"] forms a word square because each word reads the same both horizontally and vertically.

b a l l
a r e a
l e a d
l a d y

Note:

  1. There are at least 1 and at most 1000 words.
  2. All words will have the exact same length.
  3. Word length is at least 1 and at most 5.
  4. Each word contains only lowercase English alphabet a-z.

 

Example 1:

Input:
["area","lead","wall","lady","ball"]

Output:
[
  [ "wall",
    "area",
    "lead",
    "lady"
  ],
  [ "ball",
    "area",
    "lead",
    "lady"
  ]
]

Explanation:
The output consists of two word squares. The order of output does not matter (just the order of words in each word square matters).

思路:用Trie基本没有异议。但我的想法是在判断words是否合法时用prefix检验。用map记录首字符和单词list,在取首单词时用map检验,也是做了几个优化,但还不是最优解。先看我的AC解。
Runtime:448ms,beats:7.46%
class TrieNode {
public:
    string word;
    TrieNode* child[26];
    TrieNode() {
        word = "";
        for (int i = 0; i < 26; i++) child[i] = nullptr;
    }
};

class Trie {
private:
    TrieNode * root;
public:
    Trie(vector<string> words) {
        root = new TrieNode();
        buildTrie(words);
    }
    void buildTrie(vector<string> words) {
        for (auto s : words) {
            TrieNode* tmpnode = root;
            for (auto c : s) {
                int idx = c - 'a';
                if (!tmpnode->child[idx]) tmpnode->child[idx] = new TrieNode();
                tmpnode = tmpnode->child[idx];
            }
            tmpnode->word = s;
        }
    }
    bool hasprefix(string prefix) {
        TrieNode* tmpnode = root;
        for (auto c : prefix) {
            if (!tmpnode->child[c - 'a']) return false;
            tmpnode = tmpnode->child[c - 'a'];
        }
        return true;
    }
    bool hasword(string word) {
        TrieNode* tmpnode = root;
        for (auto c : word) {
            if (!tmpnode->child[c - 'a']) return false;
            tmpnode = tmpnode->child[c - 'a'];
        }
        return tmpnode->word != "";
    }
};


bool isvalid(vector<string> words, Trie& trie) {
    int l = words.size();
    for (int i = 0; i < l; i++) {
        string prefix = "";
        for (int j = 0; j < l; j++) {
            prefix += words[j][i];
        }
        if (prefix != words[i].substr(0, prefix.size())) {
            return false;
        }
    }
  for(int i=l; i<words[0].size();i++){
    string prefix = "";
    for(int j=0; j<l; j++){
      prefix += words[j][i];
    }
    if(!trie.hasprefix(prefix)) return false;
  }
    return true;
}

void dfs(vector<vector<string>>& ret, unordered_map<char, vector<string>>& map, vector<string>& path, Trie& trie, set<string>& used, int idx) {
    if (idx == path[0].size()) {
        ret.push_back(path);
        return;
    }
    vector<string> wordlist = map[path[0][idx]];
    for (int i = 0; i<wordlist.size(); i++) {
        if (used.count(wordlist[i])) continue;
        //used.insert(wordlist[i]);
        path.push_back(wordlist[i]);
        if (isvalid(path, trie)) {
            dfs(ret, map, path, trie, used, idx + 1);
        }
        path.pop_back();
        //used.erase(wordlist[i]);
    }
}


class Solution {
public:
    vector<vector<string>> wordSquares(vector<string>& words) {
    sort(words.begin(),words.end());
        Trie trie = Trie(words);
        vector<vector<string>> ret;
        set<string> used;
        unordered_map<char, vector<string>> map;
        for (auto s : words) map[s[0]].push_back(s);
        for (auto s : words) {
            bool ban = false;
            for (char c : s) {
                if (!map.count(c)) {
                    ban = true;
                    break;
                }
            }
            if (ban) continue;
            vector<string> path;
            path.push_back(s);
            //used.insert(s);
            dfs(ret, map, path, trie, used, 1);
      //used.erase(s);
        }
        return ret;
    }
};

下面网上看到的最快的一个解法。它的TrieNode还带了一个vector,记录该Node的prefix index,好处就是在DFS的时候,能直接找到该节点的前缀vector,在这个vector中遍历进行下一层DFS即可。

Runtime: 16ms  beats: 99.63%

class Solution {
    struct TrieNode {
        vector<int> prefix;
        TrieNode* childs[26];
        TrieNode() {
            memset(childs, 0, sizeof(childs));
        }
    };
    TrieNode* build(vector<string> words) {
        TrieNode* root = new TrieNode();
        for (int i = 0; i < words.size(); i++) {
            TrieNode* p = root;
            for (auto c : words[i]) {
                if (!p->childs[c - 'a']) p->childs[c-'a'] = new TrieNode();
                p = p -> childs[c-'a'];
                p->prefix.push_back(i);
            }
        }
    return root;
    }
    void helper(vector<vector<string>>& ret, vector<string>& board, vector<string>& words, TrieNode* root, int row) {
        if (row == words[0].size()) {
            ret.push_back(board);
            return;
        }
    TrieNode* tmp = root;
        for (int i = 0; i < row; i++) {
            if (!tmp->childs[board[i][row] - 'a']) return;
            tmp = tmp->childs[board[i][row] - 'a'];
        }
        for (int i : tmp->prefix) {
            board[row] = words[i];
            helper(ret, board, words, root, row + 1);
        }
    }
public:
    vector<vector<string>> wordSquares(vector<string>& words) {
    sort(words.begin(),words.end());
        int n = words[0].size();
        TrieNode* root = build(words);
        vector<vector<string>> ret;
        vector<string> board(n);
        for (int i = 0; i < words.size(); i++) {
            board[0] = words[i];
            helper(ret, board, words, root, 1);
        }
        return ret;
    }
};















猜你喜欢

转载自www.cnblogs.com/ethanhong/p/10147217.html