zoukankan      html  css  js  c++  java
  • LC 425. Word Squares 【lock,hard】

    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;
        }
    };















  • 相关阅读:
    UVA 11925 Generating Permutations 生成排列 (序列)
    UVA 1611 Crane 起重机 (子问题)
    UVA 11572 Unique snowflakes (滑窗)
    UVA 177 PaperFolding 折纸痕 (分形,递归)
    UVA 11491 Erasing and Winning 奖品的价值 (贪心)
    UVA1610 PartyGame 聚会游戏(细节题)
    UVA 1149 Bin Packing 装箱(贪心)
    topcpder SRM 664 div2 A,B,C BearCheats , BearPlays equalPiles , BearSorts (映射)
    UVA 1442 Cave 洞穴 (贪心+扫描)
    UVA 1609 Foul Play 不公平竞赛 (构(luan)造(gao)+递归)
  • 原文地址:https://www.cnblogs.com/ethanhong/p/10147217.html
Copyright © 2011-2022 走看看