Welcome to Subscribe On Youtube

820. Short Encoding of Words

Description

A valid encoding of an array of words is any reference string s and array of indices indices such that:

  • words.length == indices.length
  • The reference string s ends with the '#' character.
  • For each index indices[i], the substring of s starting from indices[i] and up to (but not including) the next '#' character is equal to words[i].

Given an array of words, return the length of the shortest reference string s possible of any valid encoding of words.

 

Example 1:

Input: words = ["time", "me", "bell"]
Output: 10
Explanation: A valid encoding would be s = "time#bell#" and indices = [0, 2, 5].
words[0] = "time", the substring of s starting from indices[0] = 0 to the next '#' is underlined in "time#bell#"
words[1] = "me", the substring of s starting from indices[1] = 2 to the next '#' is underlined in "time#bell#"
words[2] = "bell", the substring of s starting from indices[2] = 5 to the next '#' is underlined in "time#bell#"

Example 2:

Input: words = ["t"]
Output: 2
Explanation: A valid encoding would be s = "t#" and indices = [0].

 

Constraints:

  • 1 <= words.length <= 2000
  • 1 <= words[i].length <= 7
  • words[i] consists of only lowercase letters.

Solutions

The main idea of ​​the title: Make full use of overlapping suffixes to make the effective encoding as short as possible.

Determine whether the current word is the suffix of other words. If so, there is no need to write it in the mnemonic string. Otherwise, it needs to be written and added with a # suffix.

Solution 2

This implementation uses sorting. It traverses the relevant values and updates its state as each value is processed. Ordering the data first makes the subsequent comparisons deterministic. After all required states have been considered, the maintained result is returned.

  • class Trie {
        Trie[] children = new Trie[26];
    }
    
    class Solution {
        public int minimumLengthEncoding(String[] words) {
            Trie root = new Trie();
            for (String w : words) {
                Trie cur = root;
                for (int i = w.length() - 1; i >= 0; i--) {
                    int idx = w.charAt(i) - 'a';
                    if (cur.children[idx] == null) {
                        cur.children[idx] = new Trie();
                    }
                    cur = cur.children[idx];
                }
            }
            return dfs(root, 1);
        }
    
        private int dfs(Trie cur, int l) {
            boolean isLeaf = true;
            int ans = 0;
            for (int i = 0; i < 26; i++) {
                if (cur.children[i] != null) {
                    isLeaf = false;
                    ans += dfs(cur.children[i], l + 1);
                }
            }
            if (isLeaf) {
                ans += l;
            }
            return ans;
        }
    }
    
    
    // Solution 2
    class Trie {
        Trie[] children = new Trie[26];
    
        int insert(String w) {
            Trie node = this;
            boolean pref = true;
            for (int i = w.length() - 1; i >= 0; --i) {
                int idx = w.charAt(i) - 'a';
                if (node.children[idx] == null) {
                    pref = false;
                    node.children[idx] = new Trie();
                }
                node = node.children[idx];
            }
            return pref ? 0 : w.length() + 1;
        }
    }
    
    class Solution {
        public int minimumLengthEncoding(String[] words) {
            Arrays.sort(words, (a, b) -> b.length() - a.length());
            int ans = 0;
            Trie trie = new Trie();
            for (String w : words) {
                ans += trie.insert(w);
            }
            return ans;
        }
    }
    
    
  • struct Trie {
        Trie* children[26] = {nullptr};
    };
    
    class Solution {
    public:
        int minimumLengthEncoding(vector<string>& words) {
            auto root = new Trie();
            for (auto& w : words) {
                auto cur = root;
                for (int i = w.size() - 1; i >= 0; --i) {
                    if (cur->children[w[i] - 'a'] == nullptr) {
                        cur->children[w[i] - 'a'] = new Trie();
                    }
                    cur = cur->children[w[i] - 'a'];
                }
            }
            return dfs(root, 1);
        }
    
    private:
        int dfs(Trie* cur, int l) {
            bool isLeaf = true;
            int ans = 0;
            for (int i = 0; i < 26; ++i) {
                if (cur->children[i] != nullptr) {
                    isLeaf = false;
                    ans += dfs(cur->children[i], l + 1);
                }
            }
            if (isLeaf) {
                ans += l;
            }
            return ans;
        }
    };
    
    
    // Solution 2
    class Trie {
    public:
        vector<Trie*> children;
        Trie()
            : children(26) {}
    
        int insert(string w) {
            Trie* node = this;
            bool pref = true;
            for (char c : w) {
                c -= 'a';
                if (!node->children[c]) {
                    pref = false;
                    node->children[c] = new Trie();
                }
                node = node->children[c];
            }
            return pref ? 0 : w.size() + 1;
        }
    };
    
    class Solution {
    public:
        int minimumLengthEncoding(vector<string>& words) {
            sort(words.begin(), words.end(), [](string& a, string& b) { return a.size() > b.size(); });
            Trie* trie = new Trie();
            int ans = 0;
            for (auto& w : words) {
                reverse(w.begin(), w.end());
                ans += trie->insert(w);
            }
            return ans;
        }
    };
    
    
  • class Trie:
        def __init__(self) -> None:
            self.children = [None] * 26
    
    
    class Solution:
        def minimumLengthEncoding(self, words: List[str]) -> int:
            root = Trie()
            for w in words:
                cur = root
                for i in range(len(w) - 1, -1, -1):
                    idx = ord(w[i]) - ord('a')
                    if cur.children[idx] == None:
                        cur.children[idx] = Trie()
                    cur = cur.children[idx]
            return self.dfs(root, 1)
    
        def dfs(self, cur: Trie, l: int) -> int:
            isLeaf, ans = True, 0
            for i in range(26):
                if cur.children[i] != None:
                    isLeaf = False
                    ans += self.dfs(cur.children[i], l + 1)
            if isLeaf:
                ans += l
            return ans
    
    
    # Solution 2
    class Trie:
        def __init__(self):
            self.children = [None] * 26
    
        def insert(self, w):
            node = self
            pref = True
            for c in w:
                idx = ord(c) - ord("a")
                if node.children[idx] is None:
                    node.children[idx] = Trie()
                    pref = False
                node = node.children[idx]
            return 0 if pref else len(w) + 1
    
    
    class Solution:
        def minimumLengthEncoding(self, words: List[str]) -> int:
            words.sort(key=lambda x: -len(x))
            trie = Trie()
            return sum(trie.insert(w[::-1]) for w in words)
    
    
  • type trie struct {
    	children [26]*trie
    }
    
    func minimumLengthEncoding(words []string) int {
    	root := new(trie)
    	for _, w := range words {
    		cur := root
    		for i := len(w) - 1; i >= 0; i-- {
    			if cur.children[w[i]-'a'] == nil {
    				cur.children[w[i]-'a'] = new(trie)
    			}
    			cur = cur.children[w[i]-'a']
    		}
    	}
    	return dfs(root, 1)
    }
    
    func dfs(cur *trie, l int) int {
    	isLeaf, ans := true, 0
    	for i := 0; i < 26; i++ {
    		if cur.children[i] != nil {
    			isLeaf = false
    			ans += dfs(cur.children[i], l+1)
    		}
    	}
    	if isLeaf {
    		ans += l
    	}
    	return ans
    }
    
    
    // Solution 2
    type Trie struct {
    	children [26]*Trie
    }
    
    func newTrie() *Trie {
    	return &Trie{}
    }
    
    func (this *Trie) insert(w string) int {
    	node := this
    	pref := true
    	for i := len(w) - 1; i >= 0; i-- {
    		idx := w[i] - 'a'
    		if node.children[idx] == nil {
    			pref = false
    			node.children[idx] = newTrie()
    		}
    		node = node.children[idx]
    	}
    	if pref {
    		return 0
    	}
    	return len(w) + 1
    }
    
    func minimumLengthEncoding(words []string) int {
    	sort.Slice(words, func(i, j int) bool { return len(words[i]) > len(words[j]) })
    	trie := newTrie()
    	ans := 0
    	for _, w := range words {
    		ans += trie.insert(w)
    	}
    	return ans
    }
    
    

All Problems

All Solutions