# Enclose given Substrings of the String in parenthesis

• Difficulty Level : Medium
• Last Updated : 19 Aug, 2022

Given a string S and a list of strings subs[] that stores the substrings of S and all the substrings are present only once, the task is to enclose the substrings of S that exists in subs[] in parentheses. If substrings in subs[] overlap each other or are consecutive then merge them into one set of parentheses.

Examples:

Input: S = “abcdefgh”, subs = {“ef”, “bc”, “g”}
Output: “a(bc)d(efg)h”
Explanation: Substrings “ef” and “g” are consecutive.
So they are enclosed within one set of parentheses.
Substring “bc” is enclosed within one set of parentheses

Input: S = “abcdefgh”, subs = [“abcde”, “bc”]
Output: “(abcde)fgh”
Explanation: Substrings “abcde” and “bc” overlap.
So they are enclosed within one set of parentheses.

Approach: The idea to solve the problem is as follows:

We can find the starting and ending index of each substring of subs[] in the string S. Then they can be considered as separate intervals and we can use the concept of merging overlapping intervals to merge them and enclose them in parentheses.

Follow the below steps to implement the idea:

• Create a list to store the opening and closing positions of each substring of subs[].
• Merge these intervals of opening and closing positions. For that do the following:
• Sort all intervals by opening position in ascending order.
• Starting with the first interval, traverse the sorted intervals and do the following for each interval:
• If the current interval is not the initial interval and it overlaps with the previous interval, merge them together.
• If not, add the current interval to the output interval list.
• Go through the merged interval list and insert the parentheses accordingly into the string S.

Below is the implementation of the above approach:

## C++

 `// C++ code to implement the approach` `#include ` `using` `namespace` `std;`   `// Function that takes a set of` `// intervals, merges overlapping and` `// contiguous intervals and` `// returns the merged intervals` `vector >` `  ``mergeIntervals(vector >& interval)` `{` `  ``// Stores the new indices after` `  ``// merging` `  ``vector > mergedInterval;`   `  ``int` `start = interval[0][0];` `  ``int` `end = interval[0][1];`   `  ``for` `(``int` `i = 1; i < interval.size(); i++) {`   `    ``// Intervals merge so update end index` `    ``if` `(interval[i][0] <= end` `        ``|| interval[i][0] == end + 1) {` `      ``end = max(end, interval[i][1]);` `    ``}` `    ``else` `{`   `      ``// Intervals don't merge so` `      ``// add current interval to` `      ``// mergedInterval` `      ``vector<``int``> al;` `      ``al.push_back(start);` `      ``al.push_back(end);` `      ``mergedInterval.push_back(al);`   `      ``// Update start and end index` `      ``start = interval[i][0];` `      ``end = interval[i][1];` `    ``}` `  ``}`   `  ``// Add last interval to merged interval` `  ``vector<``int``> al;` `  ``al.push_back(start);` `  ``al.push_back(end);` `  ``mergedInterval.push_back(al);`   `  ``return` `mergedInterval;` `}` `// Function finds the starting and` `// ending position of` `// substring in given input string` `vector<``int``> findSubStringIndex(string subStr, string s)` `{` `  ``int` `i = 0, j = subStr.length();` `  ``while` `(j <= s.length()) {` `    ``if` `(s.substr(i, j - i) == subStr) {` `      ``return` `{ i, j - 1 };` `    ``}` `    ``j++;` `    ``i++;` `  ``}` `  ``return` `{};` `}` `// Function to add parentheses at given index` `string addParentheses(string s, string subs[])` `{` `  ``// Interval stores the opening,` `  ``// closing position of each` `  ``// substring in subs` `  ``vector > interval(subs->size(),` `                                ``vector<``int``>(2));`   `  ``// Loop through each substring in` `  ``// subs and add the opening and` `  ``// closing positions into intervals` `  ``for` `(``int` `i = 0; i < subs->size(); i++) {` `    ``interval[i] = findSubStringIndex(subs[i], s);` `  ``}`   `  ``// Sort the intervals according to` `  ``// opening index position` `  ``sort(begin(interval), end(interval));`   `  ``vector > mergedInterval` `    ``= mergeIntervals(interval);`   `  ``string sb;` `  ``int` `pre = 0;`   `  ``// Add the opening and closing` `  ``// brackets at the positions from` `  ``// mergedIntervals` `  ``for` `(``auto``& arr : mergedInterval) {` `    ``sb += s.substr(pre, arr[0] - pre);` `    ``sb += ``'('``;` `    ``sb += s.substr(arr[0], arr[1] + 1 - arr[0]);` `    ``sb += ``')'``;` `    ``pre = arr[1] + 1;` `  ``}` `  ``sb += s.substr(pre, s.size() - pre);` `  ``return` `sb;` `}`   `// Driver Code` `int` `main()` `{` `  ``string S = ``"abcdefgh"``;` `  ``string subs[] = { ``"ef"``, ``"bc"``, ``"g"` `};`   `  ``// Function call` `  ``cout << addParentheses(S, subs) << ``"\n"``;` `  ``return` `0;` `}`   `// This code is contributed by Rohit Pradhan`

## Java

 `// Java code to implement the approach`   `import` `java.io.*;` `import` `java.util.*;`   `class` `GFG {`   `    ``// Function to add parentheses at given index` `    ``static` `String addParentheses(String s,` `                                 ``String[] subs)` `    ``{` `        ``// Interval stores the opening,` `        ``// closing position of each` `        ``// substring in subs` `        ``int``[][] interval = ``new` `int``[subs.length][``2``];`   `        ``// Loop through each substring in` `        ``// subs and add the opening and` `        ``// closing positions into intervals` `        ``for` `(``int` `i = ``0``; i < subs.length; i++) {` `            ``interval[i] = findSubStringIndex(subs[i], s);` `        ``}`   `        ``// Sort the intervals according to` `        ``// opening index position` `        ``Arrays.sort(interval, (a, b) -> a[``0``] - b[``0``]);`   `        ``ArrayList > mergedInterval` `            ``= mergeIntervals(interval);`   `        ``StringBuilder sb = ``new` `StringBuilder();` `        ``int` `pre = ``0``;`   `        ``// Add the opening and closing` `        ``// brackets at the positions from` `        ``// mergedIntervals` `        ``for` `(ArrayList arr : mergedInterval) {` `            ``sb.append(s.substring(pre, arr.get(``0``)));` `            ``sb.append(``"("``);` `            ``sb.append(` `                ``s.substring(arr.get(``0``),` `                            ``arr.get(``1``) + ``1``));` `            ``sb.append(``")"``);` `            ``pre = arr.get(``1``) + ``1``;` `        ``}` `        ``sb.append(s.substring(pre, s.length()));` `        ``String ans = ``new` `String(sb);`   `        ``return` `ans;` `    ``}`   `    ``// Function that takes a set of` `    ``// intervals, merges overlapping and` `    ``// contiguous intervals and` `    ``// returns the merged intervals` `    ``private` `static` `ArrayList >` `    ``mergeIntervals(``int``[][] interval)` `    ``{`   `        ``// Stores the new indices after` `        ``// merging` `        ``ArrayList > mergedInterval` `            ``= ``new` `ArrayList<>();`   `        ``int` `start = interval[``0``][``0``];` `        ``int` `end = interval[``0``][``1``];`   `        ``for` `(``int` `i = ``1``; i < interval.length; i++) {`   `            ``// Intervals merge so update end index` `            ``if` `(interval[i][``0``] <= end` `                ``|| interval[i][``0``] == end + ``1``) {` `                ``end = Math.max(end,` `                               ``interval[i][``1``]);` `            ``}` `            ``else` `{`   `                ``// Intervals don't merge so` `                ``// add current interval to` `                ``// mergedInterval` `                ``ArrayList al` `                    ``= ``new` `ArrayList<>();` `                ``al.add(start);` `                ``al.add(end);` `                ``mergedInterval.add(al);`   `                ``// Update start and end index` `                ``start = interval[i][``0``];` `                ``end = interval[i][``1``];` `            ``}` `        ``}`   `        ``// Add last interval to merged interval` `        ``ArrayList al` `            ``= ``new` `ArrayList<>();` `        ``al.add(start);` `        ``al.add(end);` `        ``mergedInterval.add(al);`   `        ``return` `mergedInterval;` `    ``}`   `    ``// Function finds the starting and` `    ``// ending position of` `    ``// substring in given input string` `    ``static` `int``[] findSubStringIndex(String subStr,` `                                    ``String s)` `    ``{` `        ``int` `i = ``0``, j = subStr.length();` `        ``while` `(j <= s.length()) {` `            ``if` `(s.substring(i, j).equals(subStr)) {` `                ``return` `new` `int``[] { i, j - ``1` `};` `            ``}` `            ``j++;` `            ``i++;` `        ``}` `        ``return` `null``;` `    ``}`   `    ``// Driver Code` `    ``public` `static` `void` `main(String[] args)` `    ``{` `        ``String S = ``"abcdefgh"``;` `        ``String[] subs = { ``"ef"``, ``"bc"``, ``"g"` `};`   `        ``// Function call` `        ``System.out.println(addParentheses(S, subs));` `    ``}` `}`

## Python3

 `# Python 3 code to implement the approach` `# Function that takes a set of` `# intervals, merges overlapping and` `# contiguous intervals and` `# returns the merged intervals` `def` `mergeIntervals(interval):` `  `  `    ``# Stores the new indices after merging` `    ``mergedInterval ``=` `[]` `    ``start ``=` `interval[``0``][``0``]` `    ``end ``=` `interval[``0``][``1``]` `    ``for` `i ``in` `range``(``1``, ``len``(interval)):` `        ``# Intervals merge so update end index` `        ``if` `interval[i][``0``] <``=` `end ``or` `interval[i][``0``] ``=``=` `end``+``1``:` `            ``end ``=` `max``(end, interval[i][``1``])` `        ``else``:` `            ``# Intervals don't merge so` `            ``# add current interval to` `            ``# mergedInterval` `            ``al ``=` `[]` `            ``al.append(start)` `            ``al.append(end)` `            ``mergedInterval.append(al)`   `            ``# Update start and end index` `            ``start ``=` `interval[i][``0``]` `            ``end ``=` `interval[i][``1``]` `    ``# Add last interval to merged interval` `    ``al ``=` `[]` `    ``al.append(start)` `    ``al.append(end)` `    ``mergedInterval.append(al)` `    ``return` `mergedInterval` `  `  `# Function finds the starting and` `# ending position of` `# substring in given input string` `def` `findSubStringIndex(subStr, s):` `    ``i ``=` `0` `    ``j ``=` `len``(subStr)` `    ``while``(j < ``len``(s)):` `        ``if` `s[i:j] ``=``=` `subStr:` `            ``return` `[i, j``-``1``]` `        ``j ``+``=` `1` `        ``i ``+``=` `1` `        `  `# Function to add parentheses at given index` `def` `addParentheses(s, subs):` `  `  `    ``# Interval stores the opening,` `    ``# closing position of each` `    ``# substring in subs` `    ``interval ``=` `[``0``]``*``len``(subs)` `    ``# Loop through each substring in` `    ``# subs and add the opening and` `    ``# closing positions into intervals`   `    ``for` `i ``in` `range``(``len``(subs)):` `        ``interval[i] ``=` `findSubStringIndex(subs[i], s)` `    ``# Sort the intervals according to` `    ``# opening index position`   `    ``interval.sort()` `    ``mergedInterval ``=` `mergeIntervals(interval)` `    ``sb ``=` `""` `    ``pre ``=` `0`   `    ``# Add the opening and closing` `    ``# brackets at the positions from` `    ``# mergedIntervals` `    ``for` `arr ``in` `mergedInterval:` `        ``sb ``+``=` `s[pre:arr[``0``]]` `        ``sb ``+``=` `'('` `        ``sb ``+``=` `s[arr[``0``]:arr[``1``] ``+` `1``]` `        ``sb ``+``=` `')'` `        ``pre ``=` `arr[``1``] ``+` `1` `    ``sb ``+``=` `s[pre:``len``(s)]` `    ``return` `sb`   `# Driver code` `S ``=` `"abcdefgh"` `subs ``=` `[``'ef'``, ``'bc'``, ``'g'``]` `print``(addParentheses(S, subs))`   `'''This code is contributed by RAJAT KUMAR...'''`

## Javascript

 ``

Output

`a(bc)d(efg)h`

Time Complexity: O(N*logN + N*M) where N is the size of subs[] and M is the length of S
Auxiliary Space: O(N)

My Personal Notes arrow_drop_up
Related Articles