<p>A <strong>valid encoding</strong> of an array of <code>words</code> is any reference string <code>s</code> and array of indices <code>indices</code> such that:</p>

<ul>
	<li><code>words.length == indices.length</code></li>
	<li>The reference string <code>s</code> ends with the <code>&#39;#&#39;</code> character.</li>
	<li>For each index <code>indices[i]</code>, the <strong>substring</strong> of <code>s</code> starting from <code>indices[i]</code> and up to (but not including) the next <code>&#39;#&#39;</code> character is equal to <code>words[i]</code>.</li>
</ul>

<p>Given an array of <code>words</code>, return <em>the <strong>length of the shortest reference string</strong> </em><code>s</code><em> possible of any <strong>valid encoding</strong> of </em><code>words</code><em>.</em></p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> words = [&quot;time&quot;, &quot;me&quot;, &quot;bell&quot;]
<strong>Output:</strong> 10
<strong>Explanation:</strong> A valid encoding would be s = <code>&quot;time#bell#&quot; and indices = [0, 2, 5</code>].
words[0] = &quot;time&quot;, the substring of s starting from indices[0] = 0 to the next &#39;#&#39; is underlined in &quot;<u>time</u>#bell#&quot;
words[1] = &quot;me&quot;, the substring of s starting from indices[1] = 2 to the next &#39;#&#39; is underlined in &quot;ti<u>me</u>#bell#&quot;
words[2] = &quot;bell&quot;, the substring of s starting from indices[2] = 5 to the next &#39;#&#39; is underlined in &quot;time#<u>bell</u>#&quot;
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> words = [&quot;t&quot;]
<strong>Output:</strong> 2
<strong>Explanation:</strong> A valid encoding would be s = &quot;t#&quot; and indices = [0].
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= words.length &lt;= 2000</code></li>
	<li><code>1 &lt;= words[i].length &lt;= 7</code></li>
	<li><code>words[i]</code> consists of only lowercase letters.</li>
</ul>

struct TrieNode{
    vector<TrieNode*> children;
    bool eof;
    int cnt;
    TrieNode()
    {
        children.assign(26, NULL);
        eof = false;
        cnt = 0;
    }
};

class Trie{
    TrieNode* root;
    int cnt;
    TrieNode* getNode()
    {
        return(new TrieNode());
    }
    
public:
    Trie()
    {
        root = getNode();
        cnt = 0;
    }
    
    void insert(string s)
    {
        int n = s.size();
        TrieNode* crawl = root;
        
        bool tflag = false;
        for(int i = n-1; i >= 0; i--)
        {
            int idx = s[i] - 'a';
            if (crawl->children[idx] == NULL)
            {
                crawl->children[idx] = getNode();
                tflag = true;
            }
            crawl = crawl->children[idx];
        }
        crawl->eof = true;
        if (tflag) cnt += n;
        if (crawl->eof)
        {
            bool nflag = false;
            for(int i = 0; i < 26; i++)
                if (crawl->children[i] != NULL)
                    nflag = true;
            if (!nflag) cnt += 1;
        }
    }
    
    int dfs(TrieNode* nd)
    {
        if (nd == NULL) return 0;
        int res = 0;
        bool leafFlag = false;
        for(int i = 0; i < 26; i++)
        {
            if (nd->children[i])
                res += dfs(nd->children[i]) + 1;
            else
                leafFlag = true;
        }
        if (nd->eof && !leafFlag)
        {
            res += 1;
        }
        return res;
    }
    
    int count()
    {
        return cnt;
        /*
        int ans = 0;
        TrieNode* crawl = root;
        ans = dfs(crawl);
        
        crawl = root;
        for(int i = 0; i < 26; i++)
            if (crawl->children[i] != NULL) ans += 1;
        return ans;*/
    }
};

class Trie2{
    TrieNode* root;
    int cnt;
    
    TrieNode* getNode()
    {
        return(new TrieNode());
    }
    
public:
    Trie2()
    {
        root = getNode();
        cnt = 0;
    }
    
    void insert(string s)
    {
        reverse(s.begin(), s.end());
        int n = s.size();
        TrieNode* crawl = root;
        
        bool dontCountFlag = false;
        bool nodeInsertedFlag = false;
        for(int i = 0; i < n; i++)
        {
            int idx = s[i] - 'a';
            if (crawl->children[idx] == NULL)
            {
                crawl->children[idx] = getNode();
                nodeInsertedFlag = true;
            }
            else
                dontCountFlag = true;
            crawl = crawl->children[idx];
        }
        crawl->eof = true;
        if (!dontCountFlag || (dontCountFlag && nodeInsertedFlag))
            cnt += (n+1);
    }
    
    int count()
    {
        return cnt;
    }
};

class Trie3{
    TrieNode* root;
    int cnt;
    
    TrieNode* getNode()
    {
        return(new TrieNode());
    }
    
public:
    Trie3()
    {
        root = getNode();
        cnt = 0;
    }
    
    void insert(string s)
    {
        int n = s.size();
        TrieNode* crawl = root;
        
        bool didAdd = false;
        for(int i = n-1; i >= 0; i--)
        {
            int idx = s[i] - 'a';
            if (crawl->children[idx] == NULL)
            {
                crawl->children[idx] = getNode();
                didAdd = true;
            }
            if (crawl->cnt > 0) cnt -= crawl->cnt, crawl->cnt = 0;
            crawl = crawl->children[idx];
        }
        
        if (didAdd)
        {
            crawl->cnt = n+1;
            cnt += (n+1);
        }
    }
    
    int count()
    {
        return cnt;
    }
};

class Solution {
public:
    int minimumLengthEncoding(vector<string>& words) {
        Trie3* myTrie = new Trie3();
        int n = words.size();
        if (n <= 0) return 0;
        
        for(string word : words) myTrie->insert(word);
        
        return myTrie->count();
    }
};

class Solution0 {
public:
    int minimumLengthEncoding(vector<string>& words) {
        unordered_set<string> good(words.begin(), words.end());
        int n = words.size();
        if (n <= 0) return 0;
        
        for(string word : words)
        {
            for(int i = 1; i < word.size(); i++)
                good.erase(word.substr(i));
        }
        
        int ans = 0;
        for(string cur : good)
            ans += (cur.size() + 1);
        
        return ans;
    }
};
78875