Lengths of maximized partitions of a string such that each character of the string appears in one substring


In this article, we will explore the problem of finding the lengths of maximized partitions of a string with unique characters. We will first understand the problem statement and then investigate both the naive and efficient approaches to solve this problem, along with their respective algorithms and time complexities. Lastly, we will implement the solution.

Problem Statement

Given a string, partition the string into as many substrings as possible such that each character of the string appears in only one substring. Return the lengths of these maximized partitions.

Naive Approach

The naive approach is to iterate through the string, recording the last occurrence of each character. Then, iterate through the string again and create partitions whenever the current character's last occurrence is found.

Algorithm (Naive)

  • Initialize an array to store the last occurrence of each character in the string.

  • Iterate through the string and record the last occurrence of each character.

  • Initialize a vector to store the lengths of the partitions.

  • Iterate through the string again and create partitions whenever the current character's last occurrence is found.

Code (Naive)

Example

Following are the programs to the above algorithm −

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int* partitionLengths(char* s, int* returnSize) {
   // Allocate memory for storing the last occurrence index of each character
   int* lastOccurrence = (int*)malloc(26 * sizeof(int));
   for (int i = 0; i < 26; i++) {
      lastOccurrence[i] = -1; // Initialize to -1, indicating character not encountered yet
   }
    
   int len = strlen(s);
   for (int i = 0; i < len; i++) {
      lastOccurrence[s[i] - 'a'] = i; // Update last occurrence index of character
   }
    
   // Allocate memory for storing partition lengths
   int* partitionLengths = (int*)malloc(len * sizeof(int));
   int start = 0, end = 0, partitionCount = 0;
    
   for (int i = 0; i < len; i++) {
      // Update end with maximum of its current value and the last occurrence index of current character
      end = (end > lastOccurrence[s[i] - 'a']) ? end : lastOccurrence[s[i] - 'a'];
        
      if (i == end) {
         // A partition has ended, calculate its length and store it
         partitionLengths[partitionCount++] = end - start + 1;
         start = i + 1; // Move the start of the next partition
      }
   }
    
   *returnSize = partitionCount; // Set the size of the result array
   return partitionLengths; // Return the array of partition lengths
}

int main() {
   char s[] = "abacdc";
   int length;
   int* lengths = partitionLengths(s, &length);
    
   printf("Lengths of maximized partitions: ");
   for (int i = 0; i < length; i++) {
      printf("%d ", lengths[i]);
   }
    
   free(lengths);
   return 0;
}

Output

Lengths of maximized partitions: 3 3
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

std::vector<int> partitionLengths(std::string s) {
   std::vector<int> lastOccurrence(26, -1);
   
   for (size_t i = 0; i < s.size(); i++) {
      lastOccurrence[s[i] - 'a'] = i;
   }
   
   std::vector<int> partitionLengths;
   int start = 0, end = 0;
   
   for (size_t i = 0; i < s.size(); i++) {
      end = std::max(end, lastOccurrence[s[i] - 'a']);
      if (i == end) {
         partitionLengths.push_back(end - start + 1);
         start = i + 1;
      }
   }
   
   return partitionLengths;
}

int main() {
   std::string s = "abacdc";
   std::vector<int> lengths = partitionLengths(s);
   
   std::cout << "Lengths of maximized partitions: ";
   for (int length : lengths) {
      std::cout << length << " ";
   }
   
   return 0;
}	  

Output

Lengths of maximized partitions: 3 3
import java.util.ArrayList;
import java.util.List;

public class Main {
   public static List<Integer> partitionLengths(String s) {
      int[] lastOccurrence = new int[26];
      for (int i = 0; i < 26; i++) {
         lastOccurrence[i] = -1; // Initialize to -1, indicating character not encountered yet
      }
        
      for (int i = 0; i < s.length(); i++) {
         lastOccurrence[s.charAt(i) - 'a'] = i; // Update last occurrence index of character
      }
        
      List<Integer> partitionLengths = new ArrayList<>(); // List to store partition lengths
      int start = 0, end = 0;
        
      for (int i = 0; i < s.length(); i++) {
         // Update end with maximum of its current value and the last occurrence index of current character
         end = Math.max(end, lastOccurrence[s.charAt(i) - 'a']);
         
         if (i == end) {
            // A partition has ended, calculate its length and store it
            partitionLengths.add(end - start + 1);
            start = i + 1; // Move the start of the next partition
         }
      }
        
      return partitionLengths;
   }

   public static void main(String[] args) {
      String s = "abacdc";
      List<Integer> lengths = partitionLengths(s);
        
      System.out.print("Lengths of maximized partitions: ");
      for (int length : lengths) {
         System.out.print(length + " ");
      }
   }
}

Output

Lengths of maximized partitions: 3 3
def partition_lengths(s):
   # Initialize a list to store the last occurrence index of each character
   last_occurrence = [-1] * 26
    
   # Update the last occurrence index of each character
   for i in range(len(s)):
      last_occurrence[ord(s[i]) - ord('a')] = i
    
   partition_lengths = []  # List to store partition lengths
   start = end = 0
    
   for i in range(len(s)):
      # Update end with maximum of its current value and the last occurrence index of current character
      end = max(end, last_occurrence[ord(s[i]) - ord('a')])
        
      if i == end:
         # A partition has ended, calculate its length and store it
         partition_lengths.append(end - start + 1)
         start = i + 1  # Move the start of the next partition
            
   return partition_lengths

def main():
   s = "abacdc"
   lengths = partition_lengths(s)
    
   print("Lengths of maximized partitions:", end=" ")
   for length in lengths:
      print(length, end=" ")

if __name__ == "__main__":
   main()

Output

Lengths of maximized partitions: 3 3

Time Complexity (Naive) − O(n), where n is the length of the string.

Efficient Approach

The efficient approach is similar to the naive approach, but instead of iterating through the string twice, we can create partitions while recording the last occurrence of each character in a single iteration.

Algorithm (Efficient)

  • Initialize an array to store the last occurrence of each character in the string.

  • Initialize a vector to store the lengths of the partitions.

  • Iterate through the string, record the last occurrence of each character, and create partitions whenever the current character's last occurrence is found.

Code (Efficient)

Example

Following are the programs to the above algorithm −

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int* partitionLengths(char* s, int* returnSize) {
   // Create an array to store the last occurrence index of each character
   int lastOccurrence[26];
   for (int i = 0; i < 26; i++) {
      lastOccurrence[i] = -1; // Initialize to -1 indicating character not encountered yet
   }
    
   int len = strlen(s);
   for (int i = 0; i < len; i++) {
      lastOccurrence[s[i] - 'a'] = i; // Update last occurrence index of character
   }
    
   // Allocate memory for storing partition lengths
   int* partitionLengths = (int*)malloc(len * sizeof(int));
   int start = 0, end = 0, partitionCount = 0;
    
   for (int i = 0; i < len; i++) {
      // Update end with maximum of its current value and the last occurrence index of current character
      end = (end > lastOccurrence[s[i] - 'a']) ? end : lastOccurrence[s[i] - 'a'];
        
      if (i == end) {
         // A partition has ended, calculate its length and store it
         partitionLengths[partitionCount++] = end - start + 1;
         start = i + 1; // Move the start of the next partition
      }
   }
    
   *returnSize = partitionCount; // Set the size of the result array
   return partitionLengths; // Return the array of partition lengths
}

int main() {
   char s[] = "abacdc";
   int length;
   int* lengths = partitionLengths(s, &length);
    
   printf("Lengths of maximized partitions: ");
   for (int i = 0; i < length; i++) {
      printf("%d ", lengths[i]); // Print the lengths of maximized partitions
   }
    
   free(lengths);
   return 0;
}

Output

Lengths of maximized partitions: 3 3
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

std::vector<int> partitionLengths(std::string s) {
   std::vector<int> lastOccurrence(26, -1);
   std::vector<int> partitionLengths;
   int start = 0, end = 0;
   
   for (size_t i = 0; i < s.size(); i++) {
      lastOccurrence[s[i] - 'a'] = i;
   }
   
   for (size_t i = 0; i < s.size(); i++) {
      end = std::max(end, lastOccurrence[s[i] - 'a']);
   
      if (i == end) {
         partitionLengths.push_back(end - start + 1);
         start = i + 1;
      }
   }
   
   return partitionLengths;
}

int main() {
   std::string s = "abacdc";
   std::vector<int> lengths = partitionLengths(s);
   
   std::cout << "Lengths of maximized partitions: ";
   for (int length : lengths) {
      std::cout << length << " ";
   }
   
   return 0;
}

Output

Lengths of maximized partitions: 3 3
import java.util.ArrayList;
import java.util.List;

public class Main {
   public static List<Integer> partitionLengths(String s) {
      // Create an array to store the last occurrence index of each character
      int[] lastOccurrence = new int[26];
      for (int i = 0; i < 26; i++) {
         lastOccurrence[i] = -1; // Initialize to -1 indicating character not encountered yet
      }
      
      List<Integer> partitionLengths = new ArrayList<>(); // List to store partition lengths
      int start = 0, end = 0;
      
      // Update the last occurrence index of each character
      for (int i = 0; i < s.length(); i++) {
         lastOccurrence[s.charAt(i) - 'a'] = i;
      }
      
      for (int i = 0; i < s.length(); i++) {
         // Update end with maximum of its current value and the last occurrence index of current character
         end = Math.max(end, lastOccurrence[s.charAt(i) - 'a']);
   
         if (i == end) {
            // A partition has ended, calculate its length and store it
            partitionLengths.add(end - start + 1);
            start = i + 1; // Move the start of the next partition
         }
      }
      
      return partitionLengths;
   }

   public static void main(String[] args) {
      String s = "abacdc";
      List<Integer> lengths = partitionLengths(s);
        
      System.out.print("Lengths of maximized partitions: ");
      for (int length : lengths) {
         System.out.print(length + " "); // Print the lengths of maximized partitions
      }
   }
}

Output

Lengths of maximized partitions: 3 3
def partition_lengths(s):
   # Initialize a list to store the last occurrence index of each character
   last_occurrence = [-1] * 26
   partition_lengths = [] # List to store partition lengths
   start = end = 0
    
   # Update the last occurrence index of each character
   for i in range(len(s)):
      last_occurrence[ord(s[i]) - ord('a')] = i
    
   for i in range(len(s)):
      # Update end with maximum of its current value and the last occurrence index of current character
      end = max(end, last_occurrence[ord(s[i]) - ord('a')])
   
      if i == end:
         # A partition has ended, calculate its length and store it
         partition_lengths.append(end - start + 1)
         start = i + 1  # Move the start of the next partition
            
   return partition_lengths

def main():
   s = "abacdc"
   lengths = partition_lengths(s)
    
   print("Lengths of maximized partitions:", end=" ")
   for length in lengths:
      print(length, end=" ")  # Print the lengths of maximized partitions

if __name__ == "__main__":
   main()

Output

Lengths of maximized partitions: 3 3

Time Complexity (Efficient) − O(n), where n is the length of the string.

Conclusion

In this article, we explored the problem of finding the lengths of maximized partitions of a string with unique characters. We discussed both the naive and efficient approaches to solve this problem, along with their algorithms and time complexities. The efficient approach, which combines recording the last occurrence of each character and creating partitions in a single iteration, provides an optimized solution. Both approaches have the same time complexity, but the efficient approach uses fewer iterations.

Updated on: 23-Oct-2023

98 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements