Given an array of words, the task is to find the shortest unique prefixes to represent each word in the given array. Assume that no word is prefix of another.
Examples:
arr[] = {"zebra", "dog", "duck", "dove"}
Output: z dog du dov
Explanation:
z => zebra
dog => dog
duck => du
dove => dovarr[] = {"geeksgeeks", "geeksquiz", "geeksforgeeks"};
Output: geeksg geeksq geeksf
A Simple Solution is to consider every prefix of every word (starting from the shortest to largest), and if that is not a prefix of any other string, then print it.
Approach:
The idea is to use trie and maintain a frequency count at each node representing how many words pass through that node. For each word, we traverse the trie along its path until we find a node with frequency 1, indicating no other word shares this prefix - the index at this point gives us the ending index of our minimum unique prefix.
Step-by-step approach:
- Build a trie with all words and maintain frequency count at each node
- For each word, traverse the trie until finding a node with frequency 1 to get its unique prefix
- Create substring from start to end index of found prefix and add to result
Trie Illustration:

// C++ program to find shortest unique
// prefix for every word in a given list
#include <bits/stdc++.h>
using namespace std;
class Node {
private:
vector<Node*> children;
int freq;
char ch;
public:
Node(char x) {
freq = 0;
ch = x;
children = vector<Node*>(26, nullptr);
}
// Insert a word into the Trie
void insert(string& word) {
Node* curr = this;
for(char c : word) {
if(curr->children[c-'a'] == nullptr) {
curr->children[c-'a'] = new Node(c);
}
curr = curr->children[c-'a'];
curr->freq++;
}
}
// Find the ending index of minimum
// unique prefix for given word
int findPrefix(string& word) {
Node* curr = this;
for(int i = 0; i < word.length(); i++) {
curr = curr->children[word[i]-'a'];
// If frequency is 1, we found the unique prefix
if(curr->freq == 1) {
return i;
}
}
return word.length() - 1;
}
void deleteTrie(Node* root) {
if (root==nullptr) return;
for (int i=0; i<26; i++) {
deleteTrie(root->children[i]);
delete root->children[i];
}
}
};
vector<string> findPrefixes(vector<string>& arr) {
int n = arr.size();
// Create root node of Trie
Node* root = new Node('*');
// Insert all words into the Trie
for(int i=0; i<n; i++) {
root->insert(arr[i]);
}
// Vector to store result prefixes
vector<string> result;
// Find minimum unique prefix for each word
for(int i=0; i<n; i++) {
string word = arr[i];
// Get ending index of minimum prefix
int endIndex = root->findPrefix(word);
// Add substring from start to endIndex to result
result.push_back(word.substr(0, endIndex + 1));
}
// Free up the trie space.
root->deleteTrie(root);
return result;
}
int main() {
vector<string> arr = {"zebra", "dog", "duck", "dove"};
vector<string> ans = findPrefixes(arr);
for (string val: ans) {
cout << val << " ";
}
cout << endl;
}
// Java program to find shortest unique
// prefix for every word in a given list
import java.util.*;
class GfG {
static String[] findPrefixes(String[] arr) {
int n = arr.length;
// Create root node of Trie
Node root = new Node('*');
// Insert all words into the Trie
for(int i = 0; i < n; i++) {
root.insert(arr[i]);
}
// Array to store result prefixes
String[] result = new String[n];
// Find minimum unique prefix for each word
for(int i = 0; i < n; i++) {
String word = arr[i];
// Get ending index of minimum prefix
int endIndex = root.findPrefix(word);
// Add substring from start to endIndex to result
result[i] = word.substring(0, endIndex + 1);
}
// Free up the trie space.
root.deleteTrie(root);
return result;
}
public static void main(String[] args) {
String[] arr = {"zebra", "dog", "duck", "dove"};
String[] ans = findPrefixes(arr);
for (String val : ans) {
System.out.print(val + " ");
}
System.out.println();
}
}
class Node {
private Node[] children;
private int freq;
private char ch;
Node(char x) {
freq = 0;
ch = x;
children = new Node[26];
}
// Insert a word into the Trie
void insert(String word) {
Node curr = this;
for(char c : word.toCharArray()) {
if(curr.children[c - 'a'] == null) {
curr.children[c - 'a'] = new Node(c);
}
curr = curr.children[c - 'a'];
curr.freq++;
}
}
// Find the ending index of minimum
// unique prefix for given word
int findPrefix(String word) {
Node curr = this;
for(int i = 0; i < word.length(); i++) {
curr = curr.children[word.charAt(i) - 'a'];
// If frequency is 1, we found the unique prefix
if(curr.freq == 1) {
return i;
}
}
return word.length() - 1;
}
void deleteTrie(Node root) {
if (root == null) return;
for (int i = 0; i < 26; i++) {
deleteTrie(root.children[i]);
root.children[i] = null;
}
}
}
# Python program to find shortest unique
# prefix for every word in a given list
class Node:
def __init__(self):
self.freq = 0
self.children = [None] * 26
# Insert a word into the Trie
def insert(self, word):
curr = self
for c in word:
if curr.children[ord(c) - ord('a')] is None:
curr.children[ord(c) - ord('a')] = Node()
curr = curr.children[ord(c) - ord('a')]
curr.freq += 1
# Find the ending index of minimum
# unique prefix for given word
def findPrefix(self, word):
curr = self
for i in range(len(word)):
curr = curr.children[ord(word[i]) - ord('a')]
# If frequency is 1, we found the unique prefix
if curr.freq == 1:
return i
return len(word) - 1
def findPrefixes(arr):
n = len(arr)
# Create root node of Trie
root = Node()
# Insert all words into the Trie
for i in range(n):
root.insert(arr[i])
# List to store result prefixes
result = []
# Find minimum unique prefix for each word
for i in range(n):
word = arr[i]
# Get ending index of minimum prefix
endIndex = root.findPrefix(word)
# Add substring from start to endIndex to result
result.append(word[:endIndex + 1])
return result
if __name__ == "__main__":
arr = ["zebra", "dog", "duck", "dove"]
ans = findPrefixes(arr)
print(" ".join(ans))
// C# program to find shortest unique
// prefix for every word in a given list
using System;
using System.Collections.Generic;
class GfG {
static List<string> findPrefixes(string[] arr) {
int n = arr.Length;
// Create root node of Trie
Node root = new Node();
// Insert all words into the Trie
for (int i = 0; i < n; i++) {
root.insert(arr[i]);
}
// List to store result prefixes
List<string> result = new List<string>();
// Find minimum unique prefix for each word
for (int i = 0; i < n; i++) {
string word = arr[i];
// Get ending index of minimum prefix
int endIndex = root.findPrefix(word);
// Add substring from start to endIndex to result
result.Add(word.Substring(0, endIndex + 1));
}
// Free up the trie space.
root.deleteTrie(root);
return result;
}
static void Main() {
string[] arr = { "zebra", "dog", "duck", "dove" };
List<string> ans = findPrefixes(arr);
Console.WriteLine(string.Join(" ", ans));
}
}
class Node {
private Node[] children;
private int freq;
public Node() {
freq = 0;
children = new Node[26];
}
// Insert a word into the Trie
public void insert(string word) {
Node curr = this;
foreach (char c in word) {
if (curr.children[c - 'a'] == null) {
curr.children[c - 'a'] = new Node();
}
curr = curr.children[c - 'a'];
curr.freq++;
}
}
// Find the ending index of minimum
// unique prefix for given word
public int findPrefix(string word) {
Node curr = this;
for (int i = 0; i < word.Length; i++) {
curr = curr.children[word[i] - 'a'];
// If frequency is 1, we found the unique prefix
if (curr.freq == 1) {
return i;
}
}
return word.Length - 1;
}
public void deleteTrie(Node root) {
if (root == null) return;
for (int i = 0; i < 26; i++) {
deleteTrie(root.children[i]);
root.children[i] = null;
}
}
}
// JavaScript program to find shortest unique
// prefix for every word in a given list
class Node {
constructor() {
this.freq = 0;
this.children = Array(26).fill(null);
}
// Insert a word into the Trie
insert(word) {
let curr = this;
for (let c of word) {
let index = c.charCodeAt(0) - 'a'.charCodeAt(0);
if (!curr.children[index]) {
curr.children[index] = new Node();
}
curr = curr.children[index];
curr.freq++;
}
}
// Find the ending index of minimum
// unique prefix for given word
findPrefix(word) {
let curr = this;
for (let i = 0; i < word.length; i++) {
curr = curr.children[word[i].charCodeAt(0) - 'a'.charCodeAt(0)];
if (curr.freq === 1) {
return i;
}
}
return word.length - 1;
}
}
function findPrefixes(arr) {
let root = new Node();
arr.forEach(word => root.insert(word));
return arr.map(word => word.substring(0, root.findPrefix(word) + 1));
}
let arr = ["zebra", "dog", "duck", "dove"];
console.log(findPrefixes(arr).join(" "));
Output
z dog du dov
Time Complexity: O(n*m) where n is the length of the array and m is the length of the longest word.
Auxiliary Space: O(n*m)