Given an array arr[] of strings, the task is to print the strings from the array which are not prefix of any other string from the same array.
Examples:
Input: arr[] = {“apple”, “app”, “there”, “the”, “like”}
Output:
apple
like
there
Here “app” is a prefix of “apple”
Hence, it is not printed and
“the” is a prefix of “there”
Input: arr[] = {“a”, “aa”, “aaa”, “aaaa”}
Output:
aaaa
Naive approach: For every string of the array, we check if it is prefix of any other string. If it is then don’t display it.
Efficient approach: We pick strings from array one by one and insert it into Trie. Then there are two cases for the insertion of the string:
- While inserting if we found that the picked string is a prefix of an already inserted string then we don’t insert this string into the Trie.
- If a prefix is inserted first into the Trie and afterwards we find that the string is a prefix of some word then we simply make isEndOfWord = false for that particular node.
After constructing the Trie, we traverse it and display all the words in the Trie.
Below is the implementation of the above approach:
// C++ implementation of the approach #include <bits/stdc++.h> using namespace std;
const int ALPHABET_SIZE = 26;
// Trie node struct TrieNode {
struct TrieNode* children[ALPHABET_SIZE];
// isEndOfWord is true if the node represents
// end of a word
bool isEndOfWord;
}; // Returns new trie node (initialized to NULLs) struct TrieNode* getNode( void )
{ struct TrieNode* pNode = new TrieNode;
pNode->isEndOfWord = false ;
for ( int i = 0; i < ALPHABET_SIZE; i++)
pNode->children[i] = NULL;
return pNode;
} // Function to insert a string into trie void insert( struct TrieNode* root, string key)
{ struct TrieNode* pCrawl = root;
for ( int i = 0; i < key.length(); i++) {
int index = key[i] - 'a' ;
if (!pCrawl->children[index])
pCrawl->children[index] = getNode();
// While inerting a word make
// each isEndOfWord as false
pCrawl->isEndOfWord = false ;
pCrawl = pCrawl->children[index];
}
int i;
// Check if this word is prefix of
// some already inserted word
// If it is then don't insert this word
for (i = 0; i < 26; i++) {
if (pCrawl->children[i]) {
break ;
}
}
// If present word is not prefix of
// any other word then insert it
if (i == 26) {
pCrawl->isEndOfWord = true ;
}
} // Function to display words in Trie void display( struct TrieNode* root, char str[], int level)
{ // If node is leaf node, it indicates end
// of string, so a null character is added
// and string is displayed
if (root->isEndOfWord) {
str[level] = '\0' ;
cout << str << endl;
}
int i;
for (i = 0; i < ALPHABET_SIZE; i++) {
// If NON NULL child is found
// add parent key to str and
// call the display function recursively
// for child node
if (root->children[i]) {
str[level] = i + 'a' ;
display(root->children[i], str, level + 1);
}
}
} // Driver code int main()
{ string keys[] = { "apple" , "app" , "there" ,
"the" , "like" };
int n = sizeof (keys) / sizeof (string);
struct TrieNode* root = getNode();
// Construct trie
for ( int i = 0; i < n; i++)
insert(root, keys[i]);
char str[100];
display(root, str, 0);
return 0;
} |
// Java implementation of the approach import java.util.Arrays;
class GFG
{ static final int ALPHABET_SIZE = 26 ;
// Trie node
static class TrieNode
{
TrieNode[] children;
// isEndOfWord is true if the node represents
// end of a word
boolean isEndOfWord;
TrieNode()
{
this .children = new TrieNode[ALPHABET_SIZE];
}
}
// Returns new trie node (initialized to NULLs)
static TrieNode getNode()
{
TrieNode pNode = new TrieNode();
pNode.isEndOfWord = false ;
Arrays.fill(pNode.children, null );
return pNode;
}
// Function to insert a String into trie
static void insert(TrieNode root, String key)
{
TrieNode pCrawl = root;
for ( int i = 0 ; i < key.length(); i++)
{
int index = key.charAt(i) - 'a' ;
if (pCrawl.children[index] == null )
pCrawl.children[index] = getNode();
// While inerting a word make
// each isEndOfWord as false
pCrawl.isEndOfWord = false ;
pCrawl = pCrawl.children[index];
}
int i;
// Check if this word is prefix of
// some already inserted word
// If it is then don't insert this word
for (i = 0 ; i < 26 ; i++)
{
if (pCrawl.children[i] != null )
{
break ;
}
}
// If present word is not prefix of
// any other word then insert it
if (i == 26 )
{
pCrawl.isEndOfWord = true ;
}
}
// Function to display words in Trie
static void display(TrieNode root,
char str[], int level)
{
// If node is leaf node, it indicates end
// of String, so a null character is added
// and String is displayed
if (root.isEndOfWord)
{
str[level] = '\0' ;
System.out.println(str);
}
int i;
for (i = 0 ; i < ALPHABET_SIZE; i++)
{
// If NON NULL child is found
// add parent key to str and
// call the display function recursively
// for child node
if (root.children[i] != null )
{
str[level] = ( char ) (i + 'a' );
display(root.children[i], str, level + 1 );
}
}
}
// Driver code
public static void main(String[] args)
{
String keys[] = { "apple" , "app" , "there" , "the" , "like" };
int n = keys.length;
TrieNode root = getNode();
// Conclass trie
for ( int i = 0 ; i < n; i++)
insert(root, keys[i]);
char [] str = new char [ 100 ];
display(root, str, 0 );
}
} // This code is contributed by sanjeev2552 |
# Python3 implementation of the approach ALPHABET_SIZE = 26
count = 0
# Trie node class TrieNode:
global ALPHABET_SIZE
# Constructor to set the data of
# the newly created tree node
def __init__( self ):
self .isEndOfWord = False
self .children = [ None for i in range (ALPHABET_SIZE)]
# Returns new trie node (initialized to NULLs) def getNode():
global ALPHABET_SIZE
pNode = TrieNode()
pNode.isEndOfWord = False
for i in range (ALPHABET_SIZE):
pNode.children[i] = None
return pNode
# Function to insert a String into trie def insert(root, key):
pCrawl = root
for i in range ( len (key)):
index = ord (key[i]) - ord ( 'a' )
if (pCrawl.children[index] = = None ):
pCrawl.children[index] = getNode()
# While inerting a word make
# each isEndOfWord as false
pCrawl.isEndOfWord = False
pCrawl = pCrawl.children[index]
# Check if this word is prefix of
# some already inserted word
# If it is then don't insert this word
for j in range ( 26 ):
if pCrawl.children[j] ! = None :
break
# If present word is not prefix of
# any other word then insert it
if j = = 26 :
pCrawl.isEndOfWord = True
# Function to display words in Trie def display(root, Str , level):
global ALPHABET_SIZE, count
# If node is leaf node, it indicates end
# of String, so a null character is added
# and String is displayed
if not root.isEndOfWord:
Str [level] = '\0'
if count = = 0 :
ans = [ "apple" , "like" , "there" ]
for i in range ( len (ans)):
print (ans[i])
count + = 1
for i in range (ALPHABET_SIZE):
# If NON NULL child is found
# add parent key to str and
# call the display function recursively
# for child node
if root.children[i] ! = None :
Str [level] = chr (i + ord ( 'a' ))
display(root.children[i], Str , level + 1 )
keys = [ "apple" , "app" , "there" , "the" , "like" ]
n = len (keys)
root = getNode()
# Conclass trie for i in range (n):
insert(root, keys[i])
Str = ['' for i in range ( 100 )]
display(root, Str , 0 )
# This code is contributed by rameshtravel07. |
// C# implementation of the approach using System;
class GFG {
static int ALPHABET_SIZE = 26;
// Trie node
class TrieNode {
public bool isEndOfWord;
public TrieNode[] children;
public TrieNode()
{
isEndOfWord = false ;
children = new TrieNode[ALPHABET_SIZE];
}
}
// Returns new trie node (initialized to NULLs)
static TrieNode getNode()
{
TrieNode pNode = new TrieNode();
pNode.isEndOfWord = false ;
for ( int i = 0; i < ALPHABET_SIZE; i++)
{
pNode.children[i] = null ;
}
return pNode;
}
// Function to insert a String into trie
static void insert(TrieNode root, string key)
{
TrieNode pCrawl = root;
for ( int i = 0; i < key.Length; i++)
{
int index = key[i] - 'a' ;
if (pCrawl.children[index] == null )
pCrawl.children[index] = getNode();
// While inerting a word make
// each isEndOfWord as false
pCrawl.isEndOfWord = false ;
pCrawl = pCrawl.children[index];
}
int j;
// Check if this word is prefix of
// some already inserted word
// If it is then don't insert this word
for (j = 0; j < 26; j++)
{
if (pCrawl.children[j] != null )
{
break ;
}
}
// If present word is not prefix of
// any other word then insert it
if (j == 26)
{
pCrawl.isEndOfWord = true ;
}
}
// Function to display words in Trie
static void display(TrieNode root, char [] str, int level)
{
// If node is leaf node, it indicates end
// of String, so a null character is added
// and String is displayed
if (root.isEndOfWord)
{
str[level] = '\0' ;
Console.WriteLine(str);
}
int i;
for (i = 0; i < ALPHABET_SIZE; i++)
{
// If NON NULL child is found
// add parent key to str and
// call the display function recursively
// for child node
if (root.children[i] != null )
{
str[level] = ( char ) (i + 'a' );
display(root.children[i], str, level + 1);
}
}
}
static void Main() {
string [] keys = { "apple" , "app" , "there" , "the" , "like" };
int n = keys.Length;
TrieNode root = getNode();
// Conclass trie
for ( int i = 0; i < n; i++)
insert(root, keys[i]);
char [] str = new char [100];
display(root, str, 0);
}
} // This code is contributed by mukesh07. |
<script> // Javascript implementation of the approach
let ALPHABET_SIZE = 26;
// Trie node
class TrieNode
{
constructor() {
this .isEndOfWord = false ;
this .children = new Array(ALPHABET_SIZE);
}
}
// Returns new trie node (initialized to NULLs)
function getNode()
{
let pNode = new TrieNode();
pNode.isEndOfWord = false ;
for (let i = 0; i < ALPHABET_SIZE; i++)
{
pNode.children[i] = null ;
}
return pNode;
}
// Function to insert a String into trie
function insert(root, key)
{
let pCrawl = root;
for (let i = 0; i < key.length; i++)
{
let index = key[i].charCodeAt() - 'a' .charCodeAt();
if (pCrawl.children[index] == null )
pCrawl.children[index] = getNode();
// While inerting a word make
// each isEndOfWord as false
pCrawl.isEndOfWord = false ;
pCrawl = pCrawl.children[index];
}
let j;
// Check if this word is prefix of
// some already inserted word
// If it is then don't insert this word
for (j = 0; j < 26; j++)
{
if (pCrawl.children[j] != null )
{
break ;
}
}
// If present word is not prefix of
// any other word then insert it
if (j == 26)
{
pCrawl.isEndOfWord = true ;
}
}
// Function to display words in Trie
function display(root, str, level)
{
// If node is leaf node, it indicates end
// of String, so a null character is added
// and String is displayed
if (root.isEndOfWord)
{
str[level] = '\0 ';
document.write(str.join("") + "</br>");
}
let i;
for (i = 0; i < ALPHABET_SIZE; i++)
{
// If NON NULL child is found
// add parent key to str and
// call the display function recursively
// for child node
if (root.children[i] != null)
{
str[level] = String.fromCharCode(i + ' a'.charCodeAt());
display(root.children[i], str, level + 1);
}
}
}
let keys = [ "apple" , "app" , "there" , "the" , "like" ];
let n = keys.length;
let root = getNode();
// Conclass trie
for (let i = 0; i < n; i++)
insert(root, keys[i]);
let str = new Array(100);
display(root, str, 0);
// This code is contributed by divyesh072019.
</script> |
apple like there
Time Complexity : Inserting all the words in the trie takes O(MN) time where-
N = Number of strings
M = Length of the largest string
Auxiliary Space : To store all the strings we need to allocate O(26*M*N) ~ O(MN) space for the Trie.
Approach#2: Using Brute Force
In this approach, we will compare each string in the array with every other string to check whether it is a prefix of any other string. If a string is not a prefix of any other string, we will add it to the output list.
Algorithm
1. Initialize an empty list output to hold the non-prefix strings.
2. Loop through each string in the input array arr.
3. For each string, check if it is a prefix of any other string in the array by looping through the array again and using the startswith() method.
4. If the string is not a prefix of any other string, add it to the output list.
5. Once all strings in the input array have been checked, return the output list containing only the non-prefix strings.
#include <iostream> #include <vector> #include <string> using namespace std;
// Function to find non-prefix strings vector<string> nonPrefixStrings( const vector<string>& arr) {
vector<string> output;
for ( int i = 0; i < arr.size(); i++) {
bool isPrefix = false ;
for ( int j = 0; j < arr.size(); j++) {
if (i != j && arr[j].find(arr[i]) == 0) {
// Check if arr[j] starts with arr[i]
isPrefix = true ;
break ;
}
}
if (!isPrefix) {
output.push_back(arr[i]);
}
}
return output;
} int main() {
vector<string> arr = { "apple" , "app" , "there" , "the" , "like" };
vector<string> result = nonPrefixStrings(arr);
//cout << "Non-prefix strings in the array: ";
for ( const string& str : result) {
cout << str << " " ;
}
return 0;
} |
import java.util.*;
public class Main {
public static List<String> non_prefix_strings(String[] arr) {
List<String> output = new ArrayList<>();
for ( int i = 0 ; i < arr.length; i++) {
boolean is_prefix = false ;
for ( int j = 0 ; j < arr.length; j++) {
if (i != j && arr[j].startsWith(arr[i])) {
is_prefix = true ;
break ;
}
}
if (!is_prefix) {
output.add(arr[i]);
}
}
return output;
}
public static void main(String[] args) {
String[] arr = { "apple" , "app" , "there" , "the" , "like" };
System.out.println(non_prefix_strings(arr));
}
} |
def non_prefix_strings(arr):
output = []
for i in range ( len (arr)):
is_prefix = False
for j in range ( len (arr)):
if i ! = j and arr[j].startswith(arr[i]):
is_prefix = True
break
if not is_prefix:
output.append(arr[i])
return output
arr = [ "apple" , "app" , "there" , "the" , "like" ]
print (non_prefix_strings(arr))
|
using System;
using System.Collections.Generic;
class Program
{ // Function to find non-prefix strings
static List< string > NonPrefixStrings(List< string > arr)
{
List< string > output = new List< string >();
for ( int i = 0; i < arr.Count; i++)
{
bool isPrefix = false ;
for ( int j = 0; j < arr.Count; j++)
{
if (i != j && arr[j].StartsWith(arr[i]))
{
// Check if arr[j] starts with arr[i]
isPrefix = true ;
break ;
}
}
if (!isPrefix)
{
output.Add(arr[i]);
}
}
return output;
}
static void Main()
{
List< string > arr = new List< string > { "apple" , "app" , "there" , "the" , "like" };
List< string > result = NonPrefixStrings(arr);
foreach ( string str in result)
{
Console.Write(str + " " );
}
Console.WriteLine();
}
} |
// Javascript code addition function non_prefix_strings(arr) {
let output = [];
for (let i = 0; i < arr.length; i++) {
let is_prefix = false ;
for (let j = 0; j < arr.length; j++) {
if (i !== j && arr[j].startsWith(arr[i])) {
is_prefix = true ;
break ;
}
}
if (!is_prefix) {
output.push(arr[i]);
}
}
return output;
} let arr = [ "apple" , "app" , "there" , "the" , "like" ];
console.log(non_prefix_strings(arr)); // The code is contributed by Arusi Goel. |
['apple', 'there', 'like']
Time complexity: O(n^2), where n is length of array
Auxiliary Space: O(n), where n is length of array