Talentd
FleetCode
Make and follow sheets.Sign in

Short Encoding of Words solution and explanation

MediumArrayHash TableStringTrie5 min read61.0% acceptanceUpdated 9 Apr 2026
Short Encoding of Words | Live Coding with Explanation | Leetcode - 820Algorithms Made Easy · 17:27 · 4K viewsWatch on YouTube
9 more videos on this problem
  1. Short Encoding of Words | Live Coding with Explanation | Leetcode - 820Algorithms Made Easy · 17:27 · 4K views
  2. Leetcode 820. Short Encoding of Words || code + explanation with exampleCode with Alisha · 8:42 · 2K views
  3. Short Encoding of Words | leetcode 820 | Sets | Live coding session 💯💯Coding Decoded · 11:50 · 1K views
  4. Leetcode - Short Encoding of Words (Python)Timothy H Chang · 13:17 · 969 views
  5. Daily Leetcode #340: Mar 06, 2021 - 820. Short Encoding of WordsProgramming Live with Larry · 11:31 · 518 views
  6. Daily Leetcode #811: Jun 20, 2022 - 820. Short Encoding of WordsProgramming Live with Larry · 13:03 · 515 views
  7. 820. Short Encoding of Words | Leetcode | City Coder | 6th MarchCity Coder · 6:20 · 230 views
  8. Short Encoding of words || Leetcode medium #820Digital Interview · 9:05 · 168 views
  9. Short Encoding of Words | LeetCode 820 | Coders CampCoders Camp · 8:08 · 159 views
  10. Short Encoding of Words | C++🔥| LeetCode Solution 820Gantavya Malviya · 9:48 · 133 views

The problem

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.

Approach overview

Problem Overview: You are given a list of words and must encode them into a single reference string where each word appears as a suffix ending with #. The goal is to minimize the total length of this encoded string by reusing suffixes whenever possible.

Approach 1: Reverse Sorting and Hash Set (O(total characters) time, O(total characters) space)

The key observation: if a word is a suffix of another word, it does not need its own encoding in the final string. For example, time already covers me. Start by inserting all words into a set for fast lookups. Then iterate through each word and remove all of its suffixes (e.g., word[i:]) from the set. After processing every word, only the words that are not suffixes of any other remain. The final encoded length is the sum of len(word) + 1 for each remaining word to account for the trailing #. This approach relies heavily on constant-time membership checks provided by a hash table and simple substring iteration on each string. It’s concise, efficient, and usually the preferred interview solution.

Approach 2: Suffix Trie (O(total characters) time, O(total characters) space)

A more structured solution builds a Trie using reversed words. Reverse every word so suffix relationships become prefix relationships, then insert characters into a Trie. Each path represents shared suffixes between words. When a word finishes at a leaf node (a node with no children added after insertion), that word contributes len(word) + 1 to the final encoding length. Words that end at internal nodes are suffixes of longer words and do not increase the encoding size. This method explicitly models suffix sharing and avoids repeated substring checks. It’s particularly useful when practicing Trie design or when problems require explicit prefix/suffix structure handling.

Recommended for interviews: The reverse sorting + set approach is typically expected in interviews because it’s short and leverages a clear suffix insight. It demonstrates strong understanding of array iteration and hash-based pruning. The Trie solution is equally optimal in complexity but more verbose; it’s valuable when the interviewer wants to see knowledge of Trie construction and suffix transformations.

Approach 1: Using Suffix Trie

This approach involves building a trie that can be used to efficiently check if one word is a suffix of another. By storing only the unique paths in the trie, the encoding length can be minimized by pointing out the redundancies where one word is a suffix of another.

class TrieNode:
    def __init__(self):
        self.children = {}

class Solution:
    def minimumLengthEncoding(self, words: List[str]) -> int:
        # Use only unique words
        words = set(words)
        # Reverse sort words by length
        words = sorted(words, key=lambda x: len(x), reverse=True)

        root = TrieNode()
        length = 0

        for word in words:
            current = root
            isNew = False
            # Insert word into the trie
            for char in reversed(word):
                if char not in current.children:
                    isNew = True
                    current.children[char] = TrieNode()
                current = current.children[char]

            # If it's a new path in trie, increase length
            if isNew:
                length += len(word) + 1

        return length
import java.util.*;

class TrieNode {
    Map<Character, TrieNode> children = new HashMap<>();
}

class Solution {
    public int minimumLengthEncoding(String[] words) {
        TrieNode root = new TrieNode();
        Set<TrieNode> leaves = new HashSet<>();

        for (String word : words) {
            TrieNode node = root;
            for (int i = word.length() - 1; i >= 0; i--) {
                node = node.children.computeIfAbsent(word.charAt(i), k -> new TrieNode());
            }
            leaves.add(node);
        }

        int length = 0;
        for (TrieNode leaf : leaves) {
            if (leaf.children.isEmpty()) {
                length += word.length() + 1;
            }
        }

        return length;
    }
}
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
using namespace std;

struct TrieNode {
    unordered_map<char, TrieNode*> children;
};

class Solution {
public:
    int minimumLengthEncoding(vector<string>& words) {
        TrieNode* root = new TrieNode();
        unordered_set<TrieNode*> leaves;

        for (auto& word : words) {
            TrieNode* node = root;
            for (int i = word.size() - 1; i >= 0; --i) {
                if (!node->children.count(word[i])) {
                    node->children[word[i]] = new TrieNode();
                }
                node = node->children[word[i]];
            }
            leaves.insert(node);
        }

        int length = 0;
        for (auto& leaf : leaves) {
            if (leaf->children.empty()) {
                length += word.length() + 1;
            }
        }

        return length;
    }
};
class TrieNode {
    constructor() {
        this.children = {};
    }
}

var minimumLengthEncoding = function(words) {
    let root = new TrieNode();
    let leaves = new Set();

    for (let word of words) {
        let node = root;
        for (let i = word.length - 1; i >= 0; i--) {
            let char = word[i];
            if (!node.children[char]) {
                node.children[char] = new TrieNode();
            }
            node = node.children[char];
        }
        leaves.add(node);
    }

    let length = 0;
    for (let leaf of leaves) {
        if (Object.keys(leaf.children).length === 0) {
            length += word.length + 1;
        }
    }

    return length;
};
using System;
using System.Collections.Generic;

class TrieNode {
    public Dictionary<char, TrieNode> children = new Dictionary<char, TrieNode>();
}

class Solution {
    public int MinimumLengthEncoding(string[] words) {
        TrieNode root = new TrieNode();
        HashSet<TrieNode> leaves = new HashSet<TrieNode>();

        foreach (string word in words) {
            TrieNode node = root;
            for (int i = word.Length - 1; i >= 0; i--) {
                if (!node.children.ContainsKey(word[i])) {
                    node.children[word[i]] = new TrieNode();
                }
                node = node.children[word[i]];
            }
            leaves.Add(node);
        }

        int length = 0;
        foreach (TrieNode leaf in leaves) {
            if (leaf.children.Count == 0) {
                length += word.Length + 1;
            }
        }

        return length;
    }
}

This solution uses a Trie (prefix tree) to store words in reversed order. It checks whether inserting a word introduces new paths in the Trie, indicating that it isn't a suffix of any word already added. For every new path, the length increases by the length of the word plus one for the '#'.

Complexity

Time Complexity: O(N * K) where N is the number of words and K is the average length of a word.
Space Complexity: O(N * K) due to the storage in the Trie.

Try this approach in the editor

Approach 2: Reverse Sorting and Set

By reverse sorting the words and checking suffix existence, it's possible to efficiently determine the redundant entries. This alternative approach utilizes set operations to ascertain unique encodings, optimizing storage by including only necessary components.

class Solution:
    def minimumLengthEncoding(self, words: List[str]) -> int:
        words = sorted(set(words), key=lambda w: w[::-1])
        unique_words = set(words)
        for word in words:
            for k in range(1, len(word)):
                unique_words.discard(word[k:])
        return sum(len(word) + 1 for word in unique_words)
import java.util.*;

class Solution {
    public int minimumLengthEncoding(String[] words) {
        Set<String> uniqueWords = new HashSet<>(Arrays.asList(words));
        List<String> sortedWords = new ArrayList<>(uniqueWords);
        Collections.sort(sortedWords, (a, b) -> b.compareTo(a));

        for (String word : sortedWords) {
            for (int i = 1; i < word.length(); i++) {
                uniqueWords.remove(word.substring(i));
            }
        }

        int length = 0;
        for (String word : uniqueWords) {
            length += word.length() + 1;
        }

        return length;
    }
}
#include <set>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

class Solution {
public:
    int minimumLengthEncoding(vector<string>& words) {
        set<string> unique_words(words.begin(), words.end());
        vector<string> sorted_words;

        for (auto& word : unique_words) {
            sorted_words.push_back(word);
        }

        sort(sorted_words.begin(), sorted_words.end(), [](const string& a, const string& b){
            return a > b;
        });

        for (auto& word : sorted_words) {
            for (size_t i = 1; i < word.size(); ++i) {
                unique_words.erase(word.substr(i));
            }
        }

        int length = 0;
        for (auto& word : unique_words) {
            length += word.size() + 1;
        }

        return length;
    }
};
var minimumLengthEncoding = function(words) {
    let uniqueWords = new Set(words);

    Array.from(uniqueWords).sort().forEach(word => {
        for (let i = 1; i < word.length; i++) {
            uniqueWords.delete(word.substring(i));
        }
    });

    let length = 0;
    uniqueWords.forEach(word => {
        length += word.length + 1;
    });

    return length;
};
using System;
using System.Collections.Generic;

class Solution {
    public int MinimumLengthEncoding(string[] words) {
        HashSet<string> uniqueWords = new HashSet<string>(words);
        List<string> sortedWords = new List<string>(uniqueWords);

        sortedWords.Sort((a, b) => string.Compare(b, a, StringComparison.Ordinal));

        foreach (string word in sortedWords) {
            for (int i = 1; i < word.Length; i++) {
                uniqueWords.Remove(word.Substring(i));
            }
        }

        int length = 0;
        foreach (string word in uniqueWords) {
            length += word.Length + 1;
        }

        return length;
    }
}

This method sorts the words by reversed string, facilitating checks for suffixes as subsequent entries. By discarding suffixes and iterating over the unique words, it computes the total length effectively.

Complexity

Time Complexity: O(N * K^2), Space Complexity: O(N * K).

Try this approach in the editor

Approach 3: Default Approach

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
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Using Suffix Trie

Time Complexity: O(N * K) where N is the number of words and K is the average length of a word.
Space Complexity: O(N * K) due to the storage in the Trie.

Reverse Sorting and Set

Time Complexity: O(N * K^2), Space Complexity: O(N * K).

Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Reverse Sorting + Hash SetO(total characters)O(total characters)Best general solution. Simple implementation with hash lookups and suffix removal.
Suffix Trie (reversed words)O(total characters)O(total characters)Useful when practicing Trie data structures or when explicit suffix sharing needs to be modeled.

Frequently asked questions

Is Short Encoding of Words easy or hard?

Short Encoding of Words is rated Medium because the key insight about suffix reuse is not immediately obvious. Once you recognize that suffix words can be removed, the remaining implementation using a set or Trie becomes straightforward.

Short Encoding of Words Python/Java solution

Most implementations either use a hash set to remove suffixes or build a reversed Trie. Both approaches translate cleanly into Python, Java, C++, C#, and JavaScript since they rely on basic string iteration, hash sets, and simple tree nodes.

How to solve Short Encoding of Words in O(n)?

Treat the total number of characters across all words as n. Insert all words into a hash set and remove every suffix of each word starting from index 1. After pruning, sum len(word) + 1 for the remaining words. Each suffix removal and lookup is O(1) average, giving O(n) total processing.

What is the best approach for Short Encoding of Words?

The reverse sorting and hash set approach is the most common solution. Insert all words into a set, then remove every suffix of each word. Only words that are not suffixes remain, and the answer is the sum of their lengths plus one for the '#' delimiter. This runs in O(total characters) time with O(total characters) space.

Is Short Encoding of Words asked at Google/Amazon/Meta?

Suffix and Trie-based string compression problems like this appear in interviews at companies such as Amazon, Google, and Meta. Interviewers use it to evaluate understanding of suffix relationships, hash-based pruning, and Trie data structures.

What data structure is used in Short Encoding of Words?

Two main structures appear in solutions: a hash set for quickly removing suffixes and a Trie for modeling shared suffix paths. The Trie version stores reversed words so suffixes become prefixes during insertion.

What is the time complexity of Short Encoding of Words?

The optimal solutions run in O(total characters) time where total characters is the sum of lengths of all words. Both the suffix Trie and the hash set suffix-removal approach process each character a constant number of times. Space complexity is also O(total characters).

Comments

Now write it yourselfClose this page and solve Short Encoding of Words in the editor, without looking.
Practise Short Encoding of Words