Open In App

Maximize String Partitions with No Common Characters

Last Updated : 27 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given a string s consisting of lowercase English letters, partition s into the maximum number of substrings such that no two substrings share a common character. Return the total number of such substrings.

Examples:

Input: s = "acbbcc" 
Output: 2
Explanation: "a" and "cbbcc" are two substrings that do not share any characters between them.

Input: str = “aaa” 
Output:
Explanation: 
Since the string consists of a single character, no partition can be performed. 

Input: s = "ababcbacadefegdehijhklij" 
Output: 3
Explanation: "ababcbaca", "defegde" and "hijhklij" are three substrings that do not share any characters between them..

[Naive Approach] Check Character Repetition at Every Point - O(n^2) Time and O(1) Space

We run two nested loops. The outer loop traverses through all indexes and keeps track of all the visited characters. The inner loop checks if the any future character matches with the visited characters. If no future character matches, we increment the partition count.

C++
#include <iostream>
#include <string>

using namespace std;

int MaxPartition(string &s)
{
    int n = s.size();
    int partitions = 0;
    bool visited[26] = {0};

    for (int i = 0; i < n; ++i)
    {
        visited[s[i] - 'a'] = true;
        bool isPartition = true;

        // Check if we have reached a
        // point after which no previously
        // seen character appears
        for (int j = i + 1; j < n; ++j)
        {
            if (visited[s[j] - 'a'])
            {
                isPartition = false;
                break;
            }
        }

        // If we reached a parition point
        if (isPartition)
            partitions++;
    }

    return partitions;
}

int main()
{
    string s = "ababcbacadefegdehijhklij";
    cout << MaxPartition(s) << endl;
    return 0;
}
Java
public class Main {
    public static int maxPartition(String s) {
        int n = s.length();
        int partitions = 0;
        boolean[] visited = new boolean[26];

        for (int i = 0; i < n; ++i) {
            visited[s.charAt(i) - 'a'] = true;
            boolean isPartition = true;

            // Check if we have reached a
            // point after which no previously
            // seen character appears
            for (int j = i + 1; j < n; ++j) {
                if (visited[s.charAt(j) - 'a']) {
                    isPartition = false;
                    break;
                }
            }

            // If we reached a partition point
            if (isPartition)
                partitions++;
        }

        return partitions;
    }

    public static void main(String[] args) {
        String s = "ababcbacadefegdehijhklij";
        System.out.println(maxPartition(s));
    }
}
Python
def max_partition(s):
    n = len(s)
    partitions = 0
    visited = [False] * 26

    for i in range(n):
        visited[ord(s[i]) - ord('a')] = True
        is_partition = True

        # Check if we have reached a
        # point after which no previously
        # seen character appears
        for j in range(i + 1, n):
            if visited[ord(s[j]) - ord('a')]:
                is_partition = False
                break

        # If we reached a partition point
        if is_partition:
            partitions += 1

    return partitions

s = "ababcbacadefegdehijhklij"
print(max_partition(s))
C#
using System;

class Program {
    public static int MaxPartition(string s) {
        int n = s.Length;
        int partitions = 0;
        bool[] visited = new bool[26];

        for (int i = 0; i < n; ++i) {
            visited[s[i] - 'a'] = true;
            bool isPartition = true;

            // Check if we have reached a
            // point after which no previously
            // seen character appears
            for (int j = i + 1; j < n; ++j) {
                if (visited[s[j] - 'a']) {
                    isPartition = false;
                    break;
                }
            }

            // If we reached a partition point
            if (isPartition)
                partitions++;
        }

        return partitions;
    }

    public static void Main() {
        string s = "ababcbacadefegdehijhklij";
        Console.WriteLine(MaxPartition(s));
    }
}
JavaScript
function maxPartition(s) {
    const n = s.length;
    let partitions = 0;
    const visited = new Array(26).fill(false);

    for (let i = 0; i < n; ++i) {
        visited[s.charCodeAt(i) - 'a'.charCodeAt(0)] = true;
        let isPartition = true;

        // Check if we have reached a
        // point after which no previously
        // seen character appears
        for (let j = i + 1; j < n; ++j) {
            if (visited[s.charCodeAt(j) - 'a'.charCodeAt(0)]) {
                isPartition = false;
                break;
            }
        }

        // If we reached a partition point
        if (isPartition)
            partitions++;
    }

    return partitions;
}

const s = "ababcbacadefegdehijhklij";
console.log(maxPartition(s));

Output
3

[Expected Approach 1] Using Greedy approach and array - O(n) Time and O(1) Space

The idea is to first initialize an array last of size 26 (to represent all lowercase English letters) with -1, which is used to store the last occurrence index of each character in the string.

Once we get last occurrence of each character, we traverse through the string again and keep track of the farthest last index so far. At any point, if current character's index is equal to the farthest index of last index so far, it means after this index, no previously see character would appear, so we have a partition just after the current index.

To implement the above logic, we initialize two variables:

  • cnt to count the number of partitions
  • a to track the farthest last occurrence of any character in the current substring.

Iterates through the string again, updating a to reflect the maximum last occurrence index encountered so far. If a matches the current index i, it means the substring can be closed at this position, forming a valid partition. The partition count (cnt) is then incremented.

This process continues until the end of the string is reached, return cnt(maximum number of partition).

C++
// C++ program to split the string
// to maximum number of substring
#include <bits/stdc++.h>
using namespace std;

// Function to find the maximum number of substrings
// such that there is no common charcater between them
int maxPartitions(string &s) {

    // Vector to store the last occurrence
    // of each character in the string
    vector<int> last(26, -1);

    // Traverse the string in reverse to record
    // the last position of each character
    for (int i = 0; i < s.size(); i++)
        last[s[i] - 'a'] = i;

    // count the number of partitions
    int cnt = 0;

    // To track the farthest last occurrence seen
    int a = -1;

    for (int i = 0; i < s.size(); i++)
    {
        a = max(last[s[i] - 'a'], a);

        // If the current index matches the
        // farthest occurrence, form a partition
        if (a == i)
            cnt++;
    }

    return cnt;
}

int main()
{
    string s = "acbbcc";
    cout << maxPartitions(s);
}
Java
// Java program to split the string
import java.util.HashMap;

public class Main {

    // Function to find the maximum number of substrings
    // such that there is no common character between them
    public static int maxPartitions(String s) {

        // HashMap to store the last occurrence
        // of each character in the string
        int[] last = new int[26];
        for (int i = 0; i < last.length; i++) {
            last[i] = -1;
        }

        // Traverse the string to record
        // the last position of each character
        for (int i = 0; i < s.length(); i++)
            last[s.charAt(i) - 'a'] = i;

        // count the number of partitions
        int cnt = 0;

        // To track the farthest last occurrence seen
        int a = -1;

        for (int i = 0; i < s.length(); i++) {
            a = Math.max(last[s.charAt(i) - 'a'], a);

            // If the current index matches the
            // farthest occurrence, form a partition
            if (a == i)
                cnt++;
        }

        return cnt;
    }

    public static void main(String[] args) {
        String s = "acbbcc";
        System.out.println(maxPartitions(s));
    }
}
Python
# Python program to split the string

def max_partitions(s):
    # List to store the last occurrence
    # of each character in the string
    last = [-1] * 26

    # Traverse the string to record
    # the last position of each character
    for i in range(len(s)):
        last[ord(s[i]) - ord('a')] = i

    # count the number of partitions
    cnt = 0

    # To track the farthest last occurrence seen
    a = -1

    for i in range(len(s)):
        a = max(last[ord(s[i]) - ord('a')], a)

        # If the current index matches the
        # farthest occurrence, form a partition
        if a == i:
            cnt += 1

    return cnt

s = 'acbbcc'
print(max_partitions(s))
C#
// C# program to split the string
using System;

class Program {

    // Function to find the maximum number of substrings
    // such that there is no common character between them
    public static int MaxPartitions(string s) {

        // Array to store the last occurrence
        // of each character in the string
        int[] last = new int[26];
        Array.Fill(last, -1);

        // Traverse the string to record
        // the last position of each character
        for (int i = 0; i < s.Length; i++)
            last[s[i] - 'a'] = i;

        // count the number of partitions
        int cnt = 0;

        // To track the farthest last occurrence seen
        int a = -1;

        for (int i = 0; i < s.Length; i++) {
            a = Math.Max(last[s[i] - 'a'], a);

            // If the current index matches the
            // farthest occurrence, form a partition
            if (a == i)
                cnt++;
        }

        return cnt;
    }

    static void Main() {
        string s = "acbbcc";
        Console.WriteLine(MaxPartitions(s));
    }
}
JavaScript
// JavaScript program to split the string

function maxPartitions(s) {
    // Array to store the last occurrence
    // of each character in the string
    let last = new Array(26).fill(-1);

    // Traverse the string to record
    // the last position of each character
    for (let i = 0; i < s.length; i++)
        last[s.charCodeAt(i) - 'a'.charCodeAt(0)] = i;

    // count the number of partitions
    let cnt = 0;

    // To track the farthest last occurrence seen
    let a = -1;

    for (let i = 0; i < s.length; i++) {
        a = Math.max(last[s.charCodeAt(i) - 'a'.charCodeAt(0)], a);

        // If the current index matches the
        // farthest occurrence, form a partition
        if (a === i)
            cnt++;
    }

    return cnt;
}

let s = 'acbbcc';
console.log(maxPartitions(s));

Output
2

[Expected Approach 2] By merging intervals - O(n) Time and O(1) Space.

The main idea is to track first and last occurrence of character and treat them as intervals (first occ, last occ).

Once we have these intervals, we need to merge overlapping ones. If two intervals overlap, it means that the characters in those intervals must be part of the same substring. The merging process ensures that we are not splitting a character across multiple partitions.

After merging all overlapping intervals, the number of separate intervals left gives the desired result.

C++
// C++ program to split the string
// to maximum number of substring
#include <bits/stdc++.h>
using namespace std;

// Function to find the maximum number of substrings
// such that there is no common charcater between them
int maxPartitions(string &s) {
       
    vector<int> first(26, -1), last(26, -1);

    for (int i = 0; i < s.size(); i++) {
        if (first[s[i] - 'a'] == -1) 
            first[s[i] - 'a'] = i;  
        last[s[i] - 'a'] = i;  
    }

    int count = 0;
    int end = 0;

    for (int i = 0; i < s.size(); i++) {
        
        // Expand interval
        end = max(end, last[s[i] - 'a']);  

        // When we reach the end of a partition
        if (i == end) {
            
            // New partition formed
            count++;  
        }
    }

    return count;
       
}

int main() {
    string s = "acbbcc";
    cout<<maxPartitions(s);
}
Java
// Java program to split the string
// to maximum number of substring
import java.util.*;

class GfG {
    
    // Function to find the maximum number of substrings
    // such that there is no common character between them
     static int maxPartitions(String s) {
        
        // Arrays to store first and last occurrence of each character
        int[] first = new int[26], last = new int[26];
        Arrays.fill(first, -1);
        Arrays.fill(last, -1);

        // Find the first and last occurrence of each character
        for (int i = 0; i < s.length(); i++) {
            if (first[s.charAt(i) - 'a'] == -1) 
                first[s.charAt(i) - 'a'] = i;  
            last[s.charAt(i) - 'a'] = i;  
        }

        int count = 0;
        int end = 0;

        // Iterate through the string to find partitions
        for (int i = 0; i < s.length(); i++) {
            
            // Expand interval
            end = Math.max(end, last[s.charAt(i) - 'a']);  

            // When we reach the end of a partition
            if (i == end) {
                
                // New partition formed
                count++;  
            }
        }

        return count;
    }

    public static void main(String[] args) {
        String s = "acbbcc";
        System.out.println(maxPartitions(s)); 
    }
}
Python
# Function to find the maximum number of substrings
# such that there is no common character between them
def maxPartitions(s):
    
    # Arrays to store first and last occurrence of each character
    first = [-1] * 26
    last = [-1] * 26

    # Find the first and last occurrence of each character
    for i in range(len(s)):
        if first[ord(s[i]) - ord('a')] == -1:
            first[ord(s[i]) - ord('a')] = i
        last[ord(s[i]) - ord('a')] = i

    count = 0
    end = 0

    # Iterate through the string to find partitions
    for i in range(len(s)):
        
        # Expand interval
        end = max(end, last[ord(s[i]) - ord('a')])

        # When we reach the end of a partition
        if i == end:
            
            # New partition formed
            count += 1  

    return count

if __name__ == "__main__":
    s = "acbbcc"
    print(maxPartitions(s))  
C#
using System;

class GfG {
    // Function to find the maximum number of substrings
    // such that there is no common character between them
    static int maxPartitions(string s) {
        
        // Arrays to store first and last occurrence of each character
        int[] first = new int[26];
        int[] last = new int[26];
        Array.Fill(first, -1);
        Array.Fill(last, -1);

        // Find the first and last occurrence of each character
        for (int i = 0; i < s.Length; i++) {
            if (first[s[i] - 'a'] == -1)
                first[s[i] - 'a'] = i;
            last[s[i] - 'a'] = i;
        }

        int count = 0;
        int end = 0;

        // Iterate through the string to find partitions
        for (int i = 0; i < s.Length; i++) {
            
            // Expand interval
            end = Math.Max(end, last[s[i] - 'a']);

            // When we reach the end of a partition
            if (i == end) {
                
                // New partition formed
                count++; 
            }
        }

        return count;
    }

    static void Main() {
        string s = "acbbcc";
        Console.WriteLine(maxPartitions(s));  
    }
}
JavaScript
// Function to find the maximum number of substrings
// such that there is no common character between them
function maxPartitions(s) {
    
    // Arrays to store first and last occurrence of each character
    let first = new Array(26).fill(-1);
    let last = new Array(26).fill(-1);

    // Find the first and last occurrence of each character
    for (let i = 0; i < s.length; i++) {
        if (first[s.charCodeAt(i) - 'a'.charCodeAt(0)] === -1) {
            first[s.charCodeAt(i) - 'a'.charCodeAt(0)] = i;
        }
        last[s.charCodeAt(i) - 'a'.charCodeAt(0)] = i;
    }

    let count = 0;
    let end = 0;

    // Iterate through the string to find partitions
    for (let i = 0; i < s.length; i++) {
        
        // Expand interval
        end = Math.max(end, last[s.charCodeAt(i) - 'a'.charCodeAt(0)]);

        // When we reach the end of a partition
        if (i === end) {
            
            // New partition formed
            count++; 
        }
    }

    return count;
}

// Driver Code 
const s = "acbbcc";
console.log(maxPartitions(s)); 

Output
2

Next Article

Similar Reads