Strings from an array which are not prefix of any other string
Last Updated :
09 Nov, 2023
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++
// 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
// 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
# 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#
// 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.
JavaScript
<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>
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.
C++
#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;
}
Java
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));
}
}
Python3
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))
C#
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
// 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.
Output['apple', 'there', 'like']
Time complexity: O(n^2), where n is length of array
Auxiliary Space: O(n), where n is length of array
Similar Reads
Computer Science Subjects