# Solution For Maximum Number Of Non Overlapping Substrings

Problem statement:

Given a string s, return an array of the maximum number of non-overlapping substrings that meet the following conditions:

• The substrings are non-empty and contain only lowercase English letters.
• Each substring is unique and appears only once in s.

You may return the answer in any order.

Example 1:

Output: [“e”,”f”,”ccc”] Explanation: The following are all the possible non-overlapping substrings that meet the conditions:
[
“ef”,
“e”,
“f”,
“ccc”,
“cc”,
“c”
] If we choose the first string, we cannot choose anything else and we’d get only 1. If we choose “adefadda” instead, then it is not possible to choose anything else.

Example 2:

Input: s = “abbaccd”
Output: [“d”,”bb”,”cc”] Explanation: The following are all the possible non-overlapping substrings that meet the conditions:
[
“abbaccd”
“abba”,
“bb”,
“a”,
“c”,
“d”,
“cc”,
“cd”
] If we choose the first string, we cannot choose anything else and we’d get only 1. If we choose “abba” instead, we have to skip “bb” to create non-overlapping substrings, so the maximum number is 3.

Solution:

We can solve this problem using the algorithm of finding palindrome substrings. The length of the palindrome substring will be the maximum length of the non-overlapping string. We can find multiple palindrome substrings with different start and end indices. We will only select the palindrome substrings that are unique and maximize the number of non-overlapping substrings.

1. First, we will find all the palindrome substrings in a string.

2. We will create a list of unique palindrome substrings.

3. We will sort the list of palindrome substrings according to the end index.

4. We will iterate through each palindrome substring from left to right and keep track of the end index of the last selected palindrome substring.

5. We will select only those palindrome substrings whose start index is greater than the end index of the last selected palindrome substring.

6. We will add the selected palindrome substring to the result list.

7. We will update the end index of the last selected palindrome substring to the end index of the current selected palindrome substring.

8. We will return the result list.

Python code:

class Solution:
def maxNumOfSubstrings(self, s: str) -> List[str]:
intervals = {}
for i in range(len(s)):
if s[i] not in intervals:
intervals[s[i]] = [i, i] intervals[s[i]] = i

``````    palindrome_subs = []
for key in intervals:
if len(intervals[key]) > 1:
start, end = intervals[key], intervals[key]
while True:
temp_start, temp_end = start - 1, end + 1
if temp_start < 0 or temp_end >= len(s) or s[temp_start] != s[temp_end]:
break
start, end = temp_start, temp_end
palindrome_subs.append([start, end])

unique_palindrome_subs = []
seen = set()
for substring in palindrome_subs:
if substring not in seen:
unique_palindrome_subs.append(substring)

unique_palindrome_subs.sort(key=lambda x: x)
result = []
last_end = -1
for substring in unique_palindrome_subs:
if substring > last_end:
result.append(s[substring:substring+1])
last_end = substring
return result
``````

## Step by Step Implementation For Maximum Number Of Non Overlapping Substrings

```class Solution {
public List maxNumOfSubstrings(String s) {
List res = new ArrayList<>();
int n = s.length();
int[] left = new int[n];
int[] right = new int[n];
Map first = new HashMap<>();
for (int i = 0; i < n; ++i) {
char c = s.charAt(i);
left[i] = first.getOrDefault(c, -1);
first.put(c, i);
}
first.clear();
for (int i = n - 1; i >= 0; --i) {
char c = s.charAt(i);
right[i] = first.getOrDefault(c, n);
first.put(c, i);
}
int j = 0, anchor = 0;
for (int i = 0; i < n; ++i) {
j = Math.max(j, left[i]);
if (i == j) {
String candidate = s.substring(anchor, i + 1);
String valid = isValid(candidate, left, right);
if (valid != null) {
if (res.size() == 0 || valid.compareTo(res.get(res.size() - 1)) > 0) {
res.clear();
} else if (valid.compareTo(res.get(res.size() - 1)) == 0) {
}
}
anchor = i + 1;
}
}
return res;
}
public String isValid(String candidate, int[] left, int[] right) {
int n = candidate.length();
int j = 0;
for (int i = 0; i < n; ++i) {
j = Math.max(j, left[i]);
if (i == j) {
if (right[j] - j < n) {
return null;
}
j = right[j];
}
}
return candidate;
}
}```
```def maxNumOfSubstrings(s):
# return a list of substrings
n = len(s)
# left[i] and right[i] represents the smallest and the largest index
# that contains the ith smallest character respectively
left, right, pos =  * 26, [n] * 26,  * 26
for i in range(n):
c = ord(s[i]) - ord('a')
if pos[c] == 0:
# if the ith smallest character has not been found yet,
# update the corresponding left and right boundary
for j in range(c + 1, 26):
if pos[j] > 0:
# if the jth smallest character has been found,
# update the ith smallest character's right boundary
# to be the jth smallest character's left boundary
right[c] = min(right[c], left[j])
left[c] = i
pos[c] = i + 1
# the list of substrings
res = []
# start represents the starting index of the current substring
start = 0
# end represents the ending index of the current substring
end = 0
for i in range(26):
if pos[i] > 0:
# if the ith smallest character has been found,
# update the current substring's ending index to be the
# ith smallest character's right boundary
end = min(end, right[i])
if i == end:
# if the current substring's ending index is equal to
# the ith smallest character's right boundary,
# meaning that the current substring does not contain
# any other character except for the ith smallest character,
# then add the current substring to the list of substrings
res.append(s[start: end])
# update the starting index of the next substring to be
# the current substring's ending index + 1
start = end + 1
return res```
```/**
* @param {string} s
* @return {string[]}
*/
var maxNumOfSubstrings = function(s) {
// edge case
if (s.length === 0) {
return [];
}

let left = 0;
let right = 0;
let result = [];

// while loop to iterate through string
while (left < s.length) {
// create a set to keep track of unique characters
let set = new Set();
// add the first character to the set
// right pointer starts at the next character
right = left + 1;

// while loop to find the rightmost boundary
while (right < s.length) {
// if the set does not contain the character
if (!set.has(s[right])) {
right++;
} else {
// if the set does contain the character
// it means we have found the right boundary
// so break out of the loop
break;
}
}

// right pointer is now at the right boundary
// so we create a substring from left to right
let substring = s.substring(left, right);

// create a variable to keep track of the leftmost boundary
// we set it to be the current left pointer
let leftmost = left;

// we iterate through the substring
for (let i = 0; i < substring.length; i++) {
// if the character is not the first character in the substring
// it means we have found the new left boundary
if (substring[i] !== substring) {
// we update the leftmost boundary
leftmost = s.indexOf(substring[i], left);
// and break out of the loop
break;
}
}

// we check if the substring is valid
// a substring is valid if it does not overlap with any other substrings
// we do this by checking if the right boundary of the substring is less than
// the left boundary of any other substrings in the result
let isValid = true;
for (let i = 0; i < result.length; i++) {
if (right < result[i].left) {
break;
} else if (right > result[i].left) {
isValid = false;
break;
}
}

// if the substring is valid, we add it to the result
if (isValid) {
result.push({
left: leftmost,
right: right,
string: substring
});
}

// update the left pointer to be the right pointer + 1
// this will start the next substring at the next character
left = right + 1;
}

// we map through the result to get an array of strings
return result.map(substring => substring.string);
};```
```We can solve this problem with a greedy approach. First, we sort the given array of strings in order of decreasing length. Then, we iterate through the array and for each string, we check if it can be added to our result without overlapping any of the other strings. If so, we add it to our result and continue. Otherwise, we move on to the next string.

vector maxNumOfNonOverlappingSubstrings(vector& A) {
// sort the array in order of decreasing length
sort(A.begin(), A.end(), [](string a, string b) {
return a.length() > b.length();
});

// our result vector
vector res;

// iterate through the array of strings
for (string& str : A) {
// check if this string can be added without overlapping
for (string& s : res) {
if (isOverlap(str, s)) {
break;
}
}

// if we can add it, do so
res.push_back(str);
}
}

return res;
}

// helper function to check if two strings overlap
bool isOverlap(string& a, string& b) {
// get the shorter and longer string
string& s = a.length() < b.length() ? a : b;
string& l = a.length() >= b.length() ? a : b;

// iterate through the shorter string
for (int i = 0; i < s.length(); i++) {
// if we find a character that exists in both strings
// at the same position, then they must overlap
if (s[i] == l[i]) {
return true;
}
}

// we didn't find any overlapping characters, so they don't overlap
return false;
}```
```using System;
using System.Collections.Generic;
using System.Linq;

public class Solution {

public IList MaxNumOfSubstrings(string s) {

//create a list to store the results
var result = new List();

//create a dictionary to store the last seen index of each character
var lastSeen = new Dictionary();

//create an array to store the left and right boundaries of each substring
var boundaries = new int[];

//iterate through the string
for (int i = 0; i < s.Length; i++) {

//get the current character
var c = s[i];

//if the character has not been seen yet, add it to the dictionary
if (!lastSeen.ContainsKey(c)) {
}

//if the character has been seen, update the right boundary of its substring
else {
boundaries[lastSeen[c]] = i;
lastSeen[c] = i;
}
}

//iterate through the boundaries array
for (int i = 0; i < boundaries.Length; i++) {

//get the current substring
var substring = s.Substring(boundaries[i], boundaries[i] - boundaries[i] + 1);

//if the substring is non-overlapping, add it to the results
if (!result.Any(x => substring.Contains(x))) {
}
}

return result;
}
}```

Scroll to Top

## Top 100 Leetcode Practice Problems In Java

Get 30% Off Instantly!
[gravityforms id="5" description="false" titla="false" ajax="true"]