Skip to content
Related Articles

Related Articles

Print a sorted list of words represented by the expression under the given grammar
  • Last Updated : 18 Jan, 2021

Given a string R(x) of length n representing an expression having the set of words under the given grammar:

  • For every lowercase letter x, R(x) = {x}
  • For expressions e_1, e_2, …, e_k with k≥2, R({e_1, e_2, …, e_k}) = R(e_1) ∪ R(e_2) ∪ … ∪ R(e_k).
  • For expressions e_1 and e_2, R(e_1 + e_2) = {a + b for (a, b) in R(e_1) × R(e_2)}, where + denotes concatenation, and × denotes the Cartesian product.

The task is to find the sorted list of words that the expression represents.

Examples:

Input: “{{a, z}, a{b, c}, {ab, z}}”
Output: [ “a”, “ab”, “ac”, “z” ]
Explanation: Each distinct word is written only once in the final answer.
{a, z}, a{b, c}, {ab, z} → {a, z}, {ab, ac}, {ab, z} → [a, z, ab, ac]

Input: “{a, b}{c, {d, e}}”
Output: [“ac”, “ad”, “ae”, “bc”, “bd”, “be”]



Approach: From the given grammar, strings can represent a set of lowercase words. Let R(expr) denote the set of words represented by the expression. Consider the following examples to understand the approach.

  • Single letters represent a singleton set containing that word.
  • R(“a”) = {“a”}
    R(“w”) = {“w”}

  • If a comma-delimited list of 2 or more expressions is encountered, take the union of possibilities.
  • R(“{a, b, c}”) = {“a”, “b”, “c”}
    R(“{{a, b}, {b, c}}”) = {“a”, “b”, “c”} (notice the final set only contains each word at most once)

  • While concatenating two expressions, take the set of possible concatenations between two words where the first word comes from the first expression and the second word comes from the second expression.
  • R(“{a, b}{c, d}”) = {“ac”, “ad”, “bc”, “bd”}
    R(“a{b, c}{d, e}f{g, h}”) = {“abdfg”, “abdfh”, “abefg”, “abefh”, “acdfg”, “acdfh”, “acefg”, “acefh”}

Follow the steps below to solve the problem:

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to implement the above approach
#include <bits/stdc++.h>
using namespace std;
  
// Function to get the Cartesian product
// of two set of strings
vector<string> getProduct(vector<string>& lhs,
                          vector<string>& rhs)
{
  
    // If lhs is empty,
    // return rhs
    if (lhs.empty())
        return rhs;
  
    // Store the Cartesian product
    // of two set of strings
    vector<string> ret;
  
    // Iterate over characters of both
    // strings and insert Cartesian product
    for (auto sl : lhs)
        for (auto sr : rhs)
            ret.push_back(sl + sr);
  
    return ret;
}
  
// Function to find the sorted list of words
// that the expression represents
vector<string> braceExpansion(string expression)
{
  
    // Store the sorted list of words
    // that the expression represents
    vector<string> ret;
  
    // Store the current set of strings
    vector<string> cur;
  
    // Append Comma
    expression += ', ';
  
    // Stores the length of expression
    int len = expression.size();
  
    // Iterate over the characters
    // of the string(expression)
    for (int i = 0; i < len; ++i) {
  
        // Stores the current character
        char c = expression[i];
  
        // If { is encountered, find
        // its closing bracket, }
        if (c == '{') {
  
            // Store the characters inside
            // of these brackets
            string sub;
  
            // Stores count of unbalanced '{''
            int cnt = 1;
  
            // Iterate over characters of
            // expression after index i
            while (++i < len) {
  
                // If current character is '{'
                if (expression[i] == '{') {
  
                    // Update cnt
                    ++cnt;
                }
  
                // If current character is '}'
                else if (expression[i] == '}') {
  
                    // Update cnt
                    --cnt;
                }
  
                // If cnt is equal to 0
                if (cnt == 0)
                    break;
  
                // Append current character
                sub += expression[i];
            }
  
            // Recursively call the function
            // for the string, sub
            vector<string> sub_ret
                = braceExpansion(sub);
  
            // Store the cartesian product of cur
            // and sub_ret in cur
            cur = getProduct(cur, sub_ret);
        }
  
        // If current character is Comma
        else if (c == ', ') {
  
            // Push cur result into ret
            ret.insert(begin(ret),
                       begin(cur), end(cur));
  
            // Clear the current set
            // of strings
            cur.clear();
        }
        else {
  
            // Append the current character to tmp
            vector<string> tmp(1, string(1, c));
  
            // Store the cartesian product of
            // tmp and cur in cur
            cur = getProduct(cur, tmp);
        }
    }
  
    // Sort the strings present in ret
    // and get only the unique set of strings
    sort(begin(ret), end(ret));
  
    auto iter = unique(begin(ret), end(ret));
  
    ret.resize(distance(begin(ret), iter));
  
    return ret;
}
  
// Driver Code
int main()
{
  
    // Given expression, str
    string str = "{a, b}{c, {d, e}}";
  
    // Store the sorted list of words
    vector<string> res;
  
    // Function Call
    res = braceExpansion(str);
  
    // Print the sorted list of words
    for (string x : res) {
        cout << x << " ";
    }
  
    return 0;
}

chevron_right


Output:

ac ad ae bc bd be

Time Complexity: O(N2)
Auxiliary Space: O(N)

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.

My Personal Notes arrow_drop_up
Recommended Articles
Page :