Given a list of strings, the task is to find the sum of all LCP (Longest Common Prefix) of maximum length by selecting any two strings at a time.
Examples:
Input: str[] = {babab, ababb, abbab, aaaaa, babaa, babbb}
Output: 6
Explanation:
Choose 1st and 5th string => length of LCP = 4,
Choose 2nd and 3rd string => length of LCP = 2
Sum of LCP = 4 + 2 = 6

Input: str = [“aa”, “aaaa”, “aaaaaaaa”, “aaaabaaaa”, “aaabaaa”]
Output: 7
Explanation:
Choose 3rd (aaaaaaaa) and 4th string (aaaabaaaa) => length of LCP (aaaa) = 4,
Choose 2nd (aaaa) and 5th (aaabaaa) string => length of LCP (aaa) = 3
Sum of LCP = 4 + 3 = 7
Naive Approach:
- Sort the list of strings in decreasing order of their length
- Then take the first string from the list and find the Longest Common Prefix with all other remaining string in the list and store it in the array
- Choose the maximum value from the array and add it to variable answer and remove the pair of string from the list corresponding to that sum
- Repeat the above procedures for all the next strings till the list is empty or you reach the last string
- The variable answer has the required sum of all LCP of maximum length
Time Complexity: O(M*N2), where M = maximum string length and N = number of strings.
Efficient Approach:
An efficient solution can be obtained using a Trie Data Structure. To find the number of characters common between the strings we will use the variable ‘visited’ to keep track of how many times one character is visited.
Following are the steps:
- Insert list of string in trie such that every string in the list is inserted as an individual trie node.
- For all prefixes of maximum length, count the pairs from deepest node in the trie.
- Use depth-first search (DFS) traversal on trie to count the pairs from deepest node.
- If the value of visited node is more than one, it means that there two or more strings that have common prefix up till that node.
- Add the value of that visited node to a variable count.
- Decrease the value of that visited node from current and previous nodes such that the pair of words chosen for calculation must be removed.
- Repeat the above steps for all nodes and return the value of count.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
class TrieNode {
public :
char val;
map< char , TrieNode*> children;
int visited;
TrieNode( char x)
{
val = x;
visited = 0;
}
};
class Trie {
public :
TrieNode* head;
Trie()
{
head = new TrieNode( '\0' );
}
void addWord(string s)
{
TrieNode* temp = head;
const unsigned int n = s.size();
for ( int i = 0; i < n; i++) {
char ch = s[i];
if (!temp->children[ch]) {
temp->children[ch] = new TrieNode(ch);
}
temp = temp->children[ch];
temp->visited++;
}
}
int dfs(TrieNode* node, int & ans, int depth)
{
int vis = 0;
for ( auto child : node->children) {
vis += dfs(child.second, ans, depth + 1);
}
node->visited -= vis;
int string_pair = 0;
if (node->visited > 1) {
string_pair = (node->visited / 2);
ans += (depth * string_pair);
node->visited -= (2 * string_pair);
}
return (2 * string_pair + vis);
}
int dfshelper()
{
int ans = 0;
dfs(head, ans, 0);
return ans;
}
};
int main()
{
Trie T;
string str[]
= { "babab" , "ababb" , "abbab" ,
"aaaaa" , "babaa" , "babbb" };
int n = 6;
for ( int i = 0; i < n; i++) {
T.addWord(str[i]);
}
int ans = T.dfshelper();
cout << ans << endl;
return 0;
}
|
Java
import java.util.*;
class GFG
{
static class TrieNode
{
char val;
HashMap<Character, TrieNode> children;
int visited;
TrieNode( char x)
{
val = x;
visited = 0 ;
children = new HashMap<>();
}
}
static class Trie
{
TrieNode head;
int ans;
Trie()
{
head = new TrieNode( '\0' );
ans = 0 ;
}
void addWord(String s)
{
TrieNode temp = head;
int n = s.length();
for ( int i = 0 ; i < n; i++)
{
char ch = s.charAt(i);
if (temp.children.get(ch) == null )
{
temp.children.put(ch, new TrieNode(ch));
}
temp = temp.children.get(ch);
temp.visited++;
}
}
int dfs(TrieNode node, int depth)
{
int vis = 0 ;
Iterator hmIterator = node.children.entrySet().iterator();
while (hmIterator.hasNext())
{
Map.Entry child = (Map.Entry)hmIterator.next();
vis += dfs((TrieNode)child.getValue(), depth + 1 );
}
node.visited -= vis;
int String_pair = 0 ;
if (node.visited > 1 )
{
String_pair = (node.visited / 2 );
ans += (depth * String_pair);
node.visited -= ( 2 * String_pair);
}
return ( 2 * String_pair + vis);
}
int dfshelper()
{
ans = 0 ;
dfs(head, 0 );
return ans;
}
}
public static void main(String args[])
{
Trie T = new Trie();
String str[]
= { "babab" , "ababb" , "abbab" ,
"aaaaa" , "babaa" , "babbb" };
int n = 6 ;
for ( int i = 0 ; i < n; i++)
{
T.addWord(str[i]);
}
int ans = T.dfshelper();
System.out.println( ans );
}
}
|
Python
class TrieNode:
def __init__( self , x):
self .val = x
self .children = {}
self .visited = 0
class Trie:
def __init__( self ):
self .head = TrieNode('')
def addWord( self , s):
temp = self .head
n = len (s)
for i in range (n):
ch = s[i]
if ch not in temp.children:
temp.children[ch] = TrieNode(ch)
temp = temp.children[ch]
temp.visited + = 1
def dfs( self , node, ans, depth):
vis = 0
for child in node.children.values():
vis + = self .dfs(child, ans, depth + 1 )
node.visited - = vis
string_pair = 0
if node.visited > 1 :
string_pair = node.visited / / 2
ans[ 0 ] + = (depth * string_pair)
node.visited - = ( 2 * string_pair)
return 2 * string_pair + vis
def dfshelper( self ):
ans = [ 0 ]
self .dfs( self .head, ans, 0 )
return ans[ 0 ]
T = Trie()
str_list = [ "babab" , "ababb" , "abbab" , "aaaaa" , "babaa" , "babbb" ]
for s in str_list:
T.addWord(s)
ans = T.dfshelper()
print (ans)
|
C#
using System;
using System.Collections.Generic;
class Program
{
class TrieNode
{
public char val;
public Dictionary< char , TrieNode> children;
public int visited;
public TrieNode( char x)
{
val = x;
visited = 0;
children = new Dictionary< char , TrieNode>();
}
}
class Trie
{
TrieNode head;
int ans;
public Trie()
{
head = new TrieNode( '\0' );
ans = 0;
}
public void addWord( string s)
{
TrieNode temp = head;
int n = s.Length;
for ( int i = 0; i < n; i++)
{
char ch = s[i];
if (!temp.children.ContainsKey(ch))
{
temp.children.Add(ch, new TrieNode(ch));
}
temp = temp.children[ch];
temp.visited++;
}
}
int dfs(TrieNode node, int depth)
{
int vis = 0;
foreach ( var child in node.children)
{
vis += dfs(child.Value, depth + 1);
}
node.visited -= vis;
int String_pair = 0;
if (node.visited > 1)
{
String_pair = (node.visited / 2);
ans += (depth * String_pair);
node.visited -= (2 * String_pair);
}
return (2 * String_pair + vis);
}
public int dfshelper()
{
ans = 0;
dfs(head, 0);
return ans;
}
}
public static void Main()
{
Trie T = new Trie();
string [] str
= { "babab" , "ababb" , "abbab" ,
"aaaaa" , "babaa" , "babbb" };
int n = 6;
for ( int i = 0; i < n; i++)
{
T.addWord(str[i]);
}
int ans = T.dfshelper();
Console.WriteLine(ans);
}
}
|
Javascript
<script>
class TrieNode
{
constructor(x)
{
this .val = x;
this .visited = 0;
this .children = new Map();
}
}
class Trie
{
constructor()
{
this .head = new TrieNode( '\0' );
this .ans = 0;
}
addWord(s)
{
let temp = this .head;
let n = s.length;
for (let i = 0; i < n; i++)
{
let ch = s[i];
if (temp.children.get(ch) == null )
{
temp.children.set(ch, new TrieNode(ch));
}
temp = temp.children.get(ch);
temp.visited++;
}
}
dfs(node,depth)
{
let vis = 0;
for (let [key, value] of node.children.entries())
{
vis += this .dfs(value, depth + 1);
}
node.visited -= vis;
let String_pair = 0;
if (node.visited > 1)
{
String_pair = (node.visited / 2);
this .ans += (depth * String_pair);
node.visited -= (2 * String_pair);
}
return (2 * String_pair + vis);
}
dfshelper()
{
this .ans = 0;
this .dfs( this .head, 0);
return this .ans;
}
}
let T = new Trie();
let str
= [ "babab" , "ababb" , "abbab" ,
"aaaaa" , "babaa" , "babbb" ];
let n = 6;
for (let i = 0; i < n; i++)
{
T.addWord(str[i]);
}
let ans = T.dfshelper();
document.write( ans );
</script>
|
Time Complexity:
For inserting all the strings in the trie: O(MN)
For performing trie traversal: O(26*M) ~ O(M)
Therefore, overall Time complexity: O(M*N), where:
N = Number of strings
M = Length of the largest string
Auxiliary Space: O(M)
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
22 Feb, 2023
Like Article
Save Article