Replacing Words with Their Shortest Root Prefix

Problem Description

In English, there exists a concept called root which can be combined with other words to form longer words called successors. To example, the root "an" combined with "other" forms the word "another".

Given a dictionary of roots and a sentence, replace all successor words in the sentence with they shortest matching root. If a successor has multiple possible roots, use the shortest one.

Examples

Input: dictionary = ["cat","bat","rat"], sentence = "the cattle was rattled by the battery"
Output: "the cat was rat by the bat"

Input: dictionary = ["a","b","c"], sentence = "aadsfasf absbs bbab cadsfafs"
Output: "a a b c"

Input: dictionary = ["a", "aa", "aaa", "aaaa"], sentence = "a aa a aaaa aaa aaa aaa aaaaaa bbb baba ababa"
Output: "a a a a a a a a bbb baba a"

Constraints

  • 1 ≤ dictionary.length ≤ 1000
  • 1 ≤ dictionary[i].length ≤ 100
  • dictionary[i] consists of lowercase letters only
  • 1 ≤ sentence.length ≤ 10^6
  • sentence consists of lowercase letters and spaces only
  • Number of words in senetnce: 1 to 1000
  • Word length in sentence: 1 to 1000
  • Words separated by single space
  • No leading or trailing spaces in sentence

Solution Approach

This problem can be efficiently solved using a Trie data structure. The Trie stores all dictionary roots, enabling quick prefix matching for each word in the sentence.

Trie Implementation

type TrieNode struct {
    children [26]*TrieNode
    isEnd    bool
}

func CreateTrie() *TrieNode {
    return &TrieNode{
        children: [26]*TrieNode{},
        isEnd:    false,
    }
}

func (trie *TrieNode) AddWord(word string) {
    current := trie
    for _, char := range word {
        index := char - 'a'
        if current.children[index] == nil {
            current.children[index] = CreateTrie()
        }
        current = current.children[index]
    }
    current.isEnd = true
}

func (trie *TrieNode) FindShortestPrefix(word string) string {
    current := trie
    var prefix strings.Builder
    
    for _, char := range word {
        idx := char - 'a'
        if current.children[idx] == nil {
            return word
        }
        
        prefix.WriteRune(char)
        current = current.children[idx]
        
        if current.isEnd {
            return prefix.String()
        }
    }
    return word
}

Main Solution Function

func replaceWordsWithPrefix(roots []string, text string) string {
    trie := CreateTrie()
    
    for _, root := range roots {
        trie.AddWord(root)
    }
    
    words := strings.Fields(text)
    for i, word := range words {
        words[i] = trie.FindShortestPrefix(word)
    }
    
    return strings.Join(words, " ")
}

Algorithm Explanation

The solution builds a Trie containing all dictionary roots. For each word in the input sentence, it traverses the Trie character by character. If a complete root is found during traversal, that root replaces the original word. If no root matches, the original word remains unchanged.

The Trie structure ensures efficient prefix matching, making this solution optimal for the given constraints.

Tags: Trie prefix-matching string-manipulation data-structures algorithm

Posted on Thu, 01 Oct 2026 16:10:25 +0000 by sgalatas