Open In App

Split a String into two Substring such that the sum of unique characters is maximum

Improve
Improve
Like Article
Like
Save
Share
Report

Given a string str, the task is to partition the string into two substrings such that the sum of unique characters of both substrings is the maximum possible.

Examples:

Input: str = “abcabcd” 
Output: 7
Explanation: Partition the given string into “abc” and “abcd”, the sum of unique characters is 3 + 4 = 7 which is maximum possible.

Input: str = “aaaaa”
Output: 2
Explanation: Partition the given string into “aa” and “aaa”, the sum of unique characters is 1 + 1 = 2 which is maximum possible. Given string can be partitioned into many other ways but this partition gives the maximum sum of unique characters.

Approach: This problem can easily be solved using prefix and suffix arrays. 

We can create a prefix array which will store the count of unique characters starting from index 0 to last index of the string. Similarly, We can create a suffix array which will store the count  of unique characters starting from the last index to 0th index. Here, set can be used to check if the current character appeared before in the iterated string or not. We can calculate the maximum sum by doing prefix[i-1] + suffix[i] for each 1 <= i < n. Take prefix[i-1] + suffix[i] so that intersecting point never counts.

Follow the steps mentioned below to implement the idea:

  • Declare two arrays of prefix and suffix
  • Declare two sets that store the visited characters so far.
  • Store prefix[i] = prefix[i-1] if the current character has already appeared, else prefix[i] = prefix[i-1] + 1
  • Store suffix[i] = suffix[i] if the current character has already appeared, else suffix[i] = suffix[i+1] + 1.
  • Declare a variable maxi = -1 which stores the maximum sum
  • Iterate through the array and compare the sum of prefix[i-1] + suffix[i] with maxi in each iteration.
  • Return maxi.

Below is the implementation of the above approach.

C++




// C++ code for the above approach:
#include <bits/stdc++.h>
using namespace std;
 
// Function for finding out maximum value
int unique_characters(string str, int n)
{
 
    // Declare set to check if the current
    // character is previously
    // appearing or not
    set<char> s1;
    set<char> s2;
 
    // Store the count of unique characters
    // from starting index.
    vector<int> prefix(n);
 
    // Store the count of unique characters
    // from last index.
    vector<int> suffix(n);
    prefix[0] = 1;
    suffix[n - 1] = 1;
    s1.insert(str[0]);
    s2.insert(str[n - 1]);
 
    // Storing the count of unique characters
    // from starting index to last index
    for (int i = 1; i < n; i++) {
 
        // If the current character has
        // appeared before, store
        // previous value
        if (s1.find(str[i]) != s1.end()) {
            prefix[i] = prefix[i - 1];
        }
        else {
            // else store previous value + 1.
            prefix[i] = prefix[i - 1] + 1;
            s1.insert(str[i]);
        }
    }
 
    // Storing the count of unique
    // characters from last index
    // to 0th index
    for (int i = n - 2; i >= 0; i--) {
 
        // If the current character has
        // already appeared, store the
        // value calculated for the
        // previous visited index of string
        if (s2.find(str[i]) != s2.end()) {
            suffix[i] = suffix[i + 1];
        }
        else {
 
            // Else store value on next index + 1.
            suffix[i] = suffix[i + 1] + 1;
            s2.insert(str[i]);
        }
    }
 
    // Store the maximum sum
    int maxi = -1;
    for (int i = 1; i < n; i++) {
 
        // Take sum of prefix[i-1] +
        // suffix[i] so that the
        // intersecting never counts.
        maxi = max(maxi, prefix[i - 1] + suffix[i]);
    }
 
    // Returning the maximum value
    return maxi;
}
 
// Driver code
int main()
{
    string str = "abcabcd";
 
    // Size of the string
    int n = str.length();
 
    // Function call
    cout << "Maximum sum is " << unique_characters(str, n);
    return 0;
}


Java




// Java code for above approach
 
import java.util.*;
 
class GFG {
    public static void main(String[] args)
    {
        String str = "abcabcd";
 
        // Size of the string
        int n = str.length();
 
        // Function call
        System.out.println("Maximum sum is "
                           + (unique_characters(str, n)));
    }
 
    public static int unique_characters(String str, int n)
    {
        // Declare set to check if the current
        // character is previously
        // appearing or not
        TreeSet<Character> s1 = new TreeSet<>();
        TreeSet<Character> s2 = new TreeSet<>();
 
        // Store the count of unique characters
        // from starting index.
        int[] prefix = new int[n];
 
        // Store the count of unique characters
        // from last index.
        int[] suffix = new int[n];
        prefix[0] = 1;
        suffix[n - 1] = 1;
        s1.add(str.charAt(0));
        s2.add(str.charAt(n - 1));
 
        // from starting index to last index
        for (int i = 1; i < n; i++) {
 
            // If the current character has
            // appeared before, store
            // previous value
            if ((s1.contains(str.charAt(i)))
                && str.charAt(i) != s1.last()) {
                prefix[i] = prefix[i - 1];
            }
            else {
                // else store previous value + 1.
                prefix[i] = prefix[i - 1] + 1;
                s1.add(str.charAt(i));
            }
        }
 
        // Storing the count of unique
        // characters from last index
        // to 0th index
        for (int i = n - 2; i >= 0; i--) {
 
            // If the current character has
            // already appeared, store the
            // value calculated for the
            // previous visited index of string
            if ((s2.contains(str.charAt(i)))
                && str.charAt(i) != s2.last()) {
                suffix[i] = suffix[i + 1];
            }
            else {
                // Else store value on next index + 1.
                suffix[i] = suffix[i + 1] + 1;
                s2.add(str.charAt(i));
            }
        }
 
        // Store the maximum sum
        int maxi = -1;
        for (int i = 1; i < n; i++) {
 
            // Take sum of prefix[i-1] +
            // suffix[i] so that the
            // intersecting never counts.
            maxi
                = Math.max(maxi, prefix[i - 1] + suffix[i]);
        }
 
        // Returning the maximum value
        return maxi;
    }
}


Python3




# Python code for the above approach:
def unique_characters(str, n):
  # Declare set to check if the current
  # character is previously
  # appearing or not
  s1 = set()
  s2 = set()
 
  # Store the count of unique characters
  # from starting index.
  prefix = [0]*n
 
  # Store the count of unique characters
  # from last index.
  suffix = [0]*n
 
  prefix[0] = 1
  suffix[n - 1] = 1
  s1.add(str[0])
  s2.add(str[n - 1])
 
  # Storing the count of unique characters
  # from starting index to last index
  for i in range(1, n):
 
      # If the current character has
      # appeared before, store
      # previous value
      if str[i] in s1:
          prefix[i] = prefix[i - 1]
      else:
          # else store previous value + 1.
          prefix[i] = prefix[i - 1] + 1
          s1.add(str[i])
 
  # Storing the count of unique
  # characters from last index
  # to 0th index
  for i in range(n-2, -1, -1):
 
      # If the current character has
      # already appeared, store the
      # value calculated for the
      # previous visited index of string
      if str[i] in s2:
          suffix[i] = suffix[i + 1]
      else:
 
          # Else store value on next index + 1.
          suffix[i] = suffix[i + 1] + 1
          s2.add(str[i])
 
  # Store the maximum sum
  maxi = -1
  for i in range(1, n):
 
      # Take sum of prefix[i-1] +
      # suffix[i] so that the
      # intersecting never counts.
      maxi = max(maxi, prefix[i - 1] + suffix[i])
 
  # Returning the maximum value
  return maxi
 
if __name__ == "__main__":
  str = "abcabcd"
  # Size of the string
  n = len(str)
 
  # Function call
  print("Maximum sum is ", unique_characters(str, n))


C#




// C# code for above approach
 
using System;
using System.Collections.Generic;
 
public class GFG {
 
    static int UniqueCharacters(string str, int n)
    {
        // Declare set to check if the current character is
        // previously appearing or not
        SortedSet<char> s1 = new SortedSet<char>();
        SortedSet<char> s2 = new SortedSet<char>();
 
        // Store the count of unique characters from
        // starting index.
        int[] prefix = new int[n];
 
        // Store the count of unique characters from last
        // index.
        int[] suffix = new int[n];
        prefix[0] = 1;
        suffix[n - 1] = 1;
        s1.Add(str[0]);
        s2.Add(str[n - 1]);
 
        // from starting index to last index
        for (int i = 1; i < n; i++) {
            // If the current character has appeared before,
            // store previous value
            if ((s1.Contains(str[i])) && str[i] != s1.Max) {
                prefix[i] = prefix[i - 1];
            }
            else {
                // else store previous value + 1.
                prefix[i] = prefix[i - 1] + 1;
                s1.Add(str[i]);
            }
        }
 
        // Storing the count of unique characters from last
        // index to 0th index
        for (int i = n - 2; i >= 0; i--) {
            // If the current character has already
            // appeared, store the value calculated for the
            // previous visited index of string
            if ((s2.Contains(str[i])) && str[i] != s2.Max) {
                suffix[i] = suffix[i + 1];
            }
            else {
                // Else store value on next index + 1.
                suffix[i] = suffix[i + 1] + 1;
                s2.Add(str[i]);
            }
        }
 
        // Store the maximum sum
        int maxi = -1;
        for (int i = 1; i < n; i++) {
            // Take sum of prefix[i-1] + suffix[i] so that
            // the intersecting never counts.
            maxi
                = Math.Max(maxi, prefix[i - 1] + suffix[i]);
        }
 
        // Returning the maximum value
        return maxi;
    }
 
    static public void Main()
    {
 
        // Code
        string str = "abcabcd";
        // Size of the string
        int n = str.Length;
 
        // Function call
        Console.WriteLine("Maximum sum is "
                          + (UniqueCharacters(str, n)));
    }
}
 
// This code is contributed by sankar.


Javascript




// JavaScript code for the above approach:
 
// Function for finding out maximum value
function uniqueCharacters(str, n) {
 
    // Declare set to check if the current
    // character is previously
    // appearing or not
    var s1 = new Set();
    var s2 = new Set();
     
    // Store the count of unique characters
    // from starting index.
    var prefix = new Array(n);
     
    // Store the count of unique characters
    // from last index.
    var suffix = new Array(n);
    prefix[0] = 1;
    suffix[n - 1] = 1;
    s1.add(str[0]);
    s2.add(str[n - 1]);
     
    // Storing the count of unique characters
    // from starting index to last index
    for (var i = 1; i < n; i++) {
     
        // If the current character has
        // appeared before, store
        // previous value
        if (s1.has(str[i])) {
            prefix[i] = prefix[i - 1];
        }
        else {
            // else store previous value + 1.
            prefix[i] = prefix[i - 1] + 1;
            s1.add(str[i]);
        }
    }
     
    // Storing the count of unique
    // characters from last index
    // to 0th index
    for (var i = n - 2; i >= 0; i--) {
     
        // If the current character has
        // already appeared, store the
        // value calculated for the
        // previous visited index of string
        if (s2.has(str[i])) {
            suffix[i] = suffix[i + 1];
        }
        else {
     
            // Else store value on next index + 1.
            suffix[i] = suffix[i + 1] + 1;
            s2.add(str[i]);
        }
    }
     
    // Store the maximum sum
    var maxi = -1;
    for (var i = 1; i < n; i++) {
     
        // Take sum of prefix[i-1] +
        // suffix[i] so that the
        // intersecting never counts.
        maxi = Math.max(maxi, prefix[i - 1] + suffix[i]);
    }
     
    // Returning the maximum value
    return maxi;
}
 
// Driver code
var str = "abcabcd";
 
// Size of the string
var n = str.length;
 
// Function call
console.log("Maximum sum is " + uniqueCharacters(str, n));
 
// This Code is Contributed by Prasad Kandekar(prasad264)


Output

Maximum value is 7

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

Efficient Approach: To solve this problem, we will use two Hash Maps and do the below steps:

  • Firstly, make a frequency map of characters and store in Hash Map characters.
  • Now, we will traverse from the start of the given string str, also we will maintain another frequency map using Hash Map freq.
  • While traversing, we will keep track of the maximum sum of the sizes of characters and freq, whenever our maximum value changes we will change our maximum pointer.
  • At last, we will return the maximum possible answer.

Implementation of the approach:

C++




#include <bits/stdc++.h>
#include <string>
#include <unordered_map>
 
using namespace std;
 
int maxUniqueCharSubstring(string str, int N)
{
    // Initializing two frequency Hash Maps
    unordered_map<char, int> characters;
    unordered_map<char, int> freq;
 
    // Making a frequency map of characters
    for (int i = 0; i < N; i++) {
        characters[str[i]]++;
    }
 
    // max variable which contains maximum sum of unique
    // characters
    int max = INT_MIN;
 
    // Traversing the string
    for (int i = 0; i < N; i++) {
        // Updating max variable
        int totalChar = (characters.size() + freq.size());
        if (max < totalChar) {
            max = totalChar;
        }
        // Updating both hash maps
        freq[str[i]]++;
        characters[str[i]]--;
 
        if (characters[str[i]] == 0) {
            characters.erase(str[i]);
        }
    }
 
    // Returning max value
    return max;
}
 
int main()
{
    string str = "abcabcd";
    int N = str.length();
    cout << "Maximum sum is "
         << maxUniqueCharSubstring(str, N) << endl;
    return 0;
}


Java




// Java algorithm for the above approach
 
import java.util.*;
 
class GFG {
    // Driver Code
    public static void main(String[] args)
    {
        String str = "abcabcd";
        int N = str.length();
        System.out.println(
            "Maximum sum is "
            + maxUniqueCharSubstring(str, N));
    }
 
    public static int maxUniqueCharSubstring(String str,
                                             int N)
    {
        // Initializing two frequency Hash Maps
        Map<Character, Integer> characters
            = new HashMap<>();
        Map<Character, Integer> freq = new HashMap<>();
 
        // Making a frequency map of characters
        for (int i = 0; i < N; i++) {
            characters.put(
                str.charAt(i),
                characters.getOrDefault(str.charAt(i), 0)
                    + 1);
        }
        // max variable which contains maximum sum of unique
        // characters
        int max = Integer.MIN_VALUE;
        // Traversing the string
        for (int i = 0; i < N; i++) {
            // Updating max variable
            if (max < characters.size() + freq.size()) {
                max = characters.size() + freq.size();
            }
            // Updating both hash maps
            freq.put(str.charAt(i),
                     freq.getOrDefault(str.charAt(i), 0)
                         + 1);
            characters.put(str.charAt(i),
                           characters.get(str.charAt(i))
                               - 1);
 
            if (characters.get(str.charAt(i)) == 0)
                characters.remove(str.charAt(i));
        }
        // Returning max value
        return max;
    }
}


Python3




# Python code for the above approach
def maxUniqueCharSubstring(string):
    # Initializing two frequency dictionaries
    characters = {}
    freq = {}
 
    # Making a frequency map of characters
    for i in string:
        if i in characters:
            characters[i] += 1
        else:
            characters[i] = 1
 
    # max variable which contains maximum sum of unique
    # characters
    max_len = float('-inf')
 
    # Traversing the string
    for i in range(len(string)):
        # Updating max variable
        if max_len < len(characters) + len(freq):
            max_len = len(characters) + len(freq)
 
        # Updating both dictionaries
        if string[i] in freq:
            freq[string[i]] += 1
        else:
            freq[string[i]] = 1
 
        characters[string[i]] = characters[string[i]] - 1
 
        if characters[string[i]] == 0:
            del characters[string[i]]
 
    # Returning max value
    return max_len
 
 
# Driver code
string = "abcabcd"
print("Maximum sum is", maxUniqueCharSubstring(string))
# This code is contributed by codearcade.


C#




// C# code for the above approach
 
using System;
using System.Collections.Generic;
 
public class GFG {
 
    public static int maxUniqueCharSubstring(string str,
                                             int N)
    {
        // Initializing two frequency Hash Maps
        Dictionary<char, int> characters
            = new Dictionary<char, int>();
        Dictionary<char, int> freq
            = new Dictionary<char, int>();
 
        // Making a frequency map of characters
        for (int i = 0; i < N; i++) {
            if (characters.ContainsKey(str[i]))
                characters[str[i]] += 1;
            else
                characters.Add(str[i], 1);
        }
 
        // max variable which contains maximum sum of unique
        // characters
        int max = int.MinValue;
 
        // Traversing the string
        for (int i = 0; i < N; i++) {
            // Updating max variable
            if (max < characters.Count + freq.Count) {
                max = characters.Count + freq.Count;
            }
 
            // Updating both hash maps
            if (freq.ContainsKey(str[i]))
                freq[str[i]] += 1;
            else
                freq.Add(str[i], 1);
 
            characters[str[i]] -= 1;
 
            if (characters[str[i]] == 0)
                characters.Remove(str[i]);
        }
 
        // Returning max value
        return max;
    }
 
    static public void Main()
    {
 
        // Code
        string str = "abcabcd";
        int N = str.Length;
        Console.WriteLine("Maximum sum is "
                          + maxUniqueCharSubstring(str, N));
    }
}
 
// This code is contributed by karthik.


Javascript




// JavaScript code for the above approach
function maxUniqueCharSubstring(str, N)
{
 
    // Initializing two frequency Hash Maps
    let characters = new Map();
    let freq = new Map();
 
    // Making a frequency map of characters
    for (let i = 0; i < N; i++) {
        characters.set(str[i], (characters.get(str[i]) || 0) + 1);
    }
 
    // max variable which contains maximum sum of unique
    // characters
    let max = Number.MIN_SAFE_INTEGER;
 
    // Traversing the string
    for (let i = 0; i < N; i++) {
        // Updating max variable
        let totalChar = (characters.size + freq.size);
        if (max < totalChar) {
            max = totalChar;
        }
 
        // Updating both hash maps
        freq.set(str[i], (freq.get(str[i]) || 0) + 1);
        characters.set(str[i], (characters.get(str[i]) || 0) - 1);
 
        if (characters.get(str[i]) === 0) {
            characters.delete(str[i]);
        }
    }
 
    // Returning max value
    return max;
}
 
let str = "abcabcd";
let N = str.length;
console.log("Maximum sum is " + maxUniqueCharSubstring(str, N));
 
// This code is contributed by prasad264


Output:

Maximum sum is 7

Time Complexity: O(N)

Auxiliary Space: Constant space is used as there can be only at most 26 characters stored in hash map.



Last Updated : 11 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads