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















  • 相关阅读:
    Window中的Docker 拉取Mysql镜像 并在本地Navicate链接
    Error response from daemon:###unable to delete ### (must be forced)
    WIN10中DOCKER的安装
    ASP.NET MVC3调用分部视图-PartialView的几种方式(集)
    jQuery select操作控制方法小结
    前置体验,才是打动用户的神器
    ASP.NET MVC form验证
    ASP.NET MVC 3 Model【通过一简单实例一步一步的介绍】
    .Net Mvc3框架调用服务端控件解决方案
    Razor基础语法简介
  • 原文地址:https://www.cnblogs.com/ethanhong/p/10147217.html
Copyright © 2020-2023  润新知