Open In App

Strings from an array which are not prefix of any other string

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: 
 

  1. 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.
  2. 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>

Output
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.

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


Article Tags :