Open In App

Partition the string in two parts such that both parts have at least k different characters

Given a string of lowercase English alphabets and an integer 0 < K <= 26. The task is to divide the string into two parts (also print them) such that both parts have at least k different characters. If there are more than one answers possible, print one having the smallest left part. If there is no such answers, print “Not Possible”.
Examples: 

Input : str = “geeksforgeeks”, k = 4 
Output : geeks , forgeeks 
The string can be divided into two parts as “geeks” and “forgeeks”. Since “geeks” has four different characters ‘g’, ‘e’, ‘k’ and ‘s’ and this is the smallest left part, “forgeeks” has also at least four different characters.

Input : str = “aaaabbbb”, k = 2 
Output :Not Possible 

 

Approach: 

Below is the implementation of the above approach 




// C++ implementation of the above approach
#include <iostream>
#include <map>
using namespace std;
 
// Function to find the partition of the
// string such that both parts have at
// least k different characters
void division_of_string(string str, int k)
{
    // Length of the string
    int n = str.size();
 
    // To check if the current
    // character is already found
    map<char, bool> has;
 
    int ans, cnt = 0, i = 0;
 
    // Count number of different
    // characters in the left part
    while (i < n) {
 
        // If current character is not
        // already found, increase cnt by 1
        if (!has[str[i]]) {
            cnt++;
            has[str[i]] = true;
        }
 
        // If count becomes equal to k, we've
        // got the first part, therefore,
        // store current index and break the loop
        if (cnt == k) {
            ans = i;
            break;
        }
 
        i++;
    }
    // Increment i by 1
    i++;
 
    // Clear the map
    has.clear();
 
    // Assign cnt as 0
    cnt = 0;
 
    while (i < n) {
 
        // If the current character is not
        // already found, increase cnt by 1
        if (!has[str[i]]) {
            cnt++;
            has[str[i]] = true;
        }
 
        // If cnt becomes equal to k, the
        // second part also have k different
        // characters so break it
        if (cnt == k) {
            break;
        }
 
        i++;
    }
 
    // If the second part has less than
    // k different characters, then
    // print "Not Possible"
    if (cnt < k) {
        cout << "Not possible" << endl;
    }
 
    // Otherwise print both parts
    else {
        i = 0;
        while (i <= ans) {
            cout << str[i];
            i++;
        }
        cout << endl;
 
        while (i < n) {
            cout << str[i];
            i++;
        }
        cout << endl;
    }
 
    cout << endl;
}
 
// Driver code
int main()
{
    string str = "geeksforgeeks";
    int k = 4;
 
    // Function call
    division_of_string(str, k);
 
    return 0;
}




// Java implementation of the approach
import java.util.*;
 
class GFG {
 
    // Function to find the partition of the
    // string such that both parts have at
    // least k different characters
    static void division_of_string(char[] str, int k)
    {
        // Length of the string
        int n = str.length;
 
        // To check if the current
        // character is already found
        Map<Character, Boolean> has = new HashMap<>();
 
        int ans = 0, cnt = 0, i = 0;
 
        // Count number of different
        // characters in the left part
        while (i < n) {
 
            // If current character is not
            // already found, increase cnt by 1
            if (!has.containsKey(str[i])) {
                cnt++;
                has.put(str[i], true);
            }
 
            // If count becomes equal to k, we've
            // got the first part, therefore,
            // store current index and break the loop
            if (cnt == k) {
                ans = i;
                break;
            }
 
            i++;
        }
        // Increment i by 1
        i++;
 
        // Clear the map
        has.clear();
 
        // Assign cnt as 0
        cnt = 0;
 
        while (i < n) {
 
            // If the current character is not
            // already found, increase cnt by 1
            if (!has.containsKey(str[i])) {
                cnt++;
                has.put(str[i], true);
            }
 
            // If cnt becomes equal to k, the
            // second part also have k different
            // characters so break it
            if (cnt == k) {
                break;
            }
 
            i++;
        }
 
        // If the second part has less than
        // k different characters, then
        // print "Not Possible"
        if (cnt < k) {
            System.out.println("Not possible");
        }
 
        // Otherwise print both parts
        else {
            i = 0;
            while (i <= ans) {
                System.out.print(str[i]);
                i++;
            }
            System.out.println("");
 
            while (i < n) {
                System.out.print(str[i]);
                i++;
            }
            System.out.println("");
        }
 
        System.out.println("");
    }
 
    // Driver code
    public static void main(String[] args)
    {
        String str = "geeksforgeeks";
        int k = 4;
 
        // Function call
        division_of_string(str.toCharArray(), k);
    }
}
 
// This code is contributed by 29AjayKumar




# Python3 implementation of the above approach
 
# Function to find the partition of the
# string such that both parts have at
# least k different characters
 
 
def division_of_string(string, k):
 
    # Length of the string
    n = len(string)
 
    # To check if the current
    # character is already found
    has = {}
 
    cnt = 0
    i = 0
 
    # Count number of different
    # characters in the left part
    while (i < n):
 
        # If current character is not
        # already found, increase cnt by 1
        if string[i] not in has:
            cnt += 1
            has[string[i]] = True
 
        # If count becomes equal to k, we've
        # got the first part, therefore,
        # store current index and break the loop
        if (cnt == k):
            ans = i
            break
 
        i += 1
 
    # Increment i by 1
    i += 1
 
    # Clear the map
    has.clear()
 
    # Assign cnt as 0
    cnt = 0
 
    while (i < n):
 
        # If the current character is not
        # already found, increase cnt by 1
        if (string[i] not in has):
            cnt += 1
            has[string[i]] = True
 
        # If cnt becomes equal to k, the
        # second part also have k different
        # characters so break it
        if (cnt == k):
            break
 
        i += 1
 
    # If the second part has less than
    # k different characters, then
    # print "Not Possible"
    if (cnt < k):
        print("Not possible", end="")
 
    # Otherwise print both parts
    else:
        i = 0
        while (i <= ans):
            print(string[i], end="")
            i += 1
 
        print()
 
        while (i < n):
            print(string[i], end="")
            i += 1
 
        print()
 
 
# Driver code
if __name__ == "__main__":
 
    string = "geeksforgeeks"
    k = 4
 
    # Function call
    division_of_string(string, k)
 
# This code is contributed by AnkitRai01




// C# implementation of the approach
using System;
using System.Collections.Generic;
 
class GFG {
 
    // Function to find the partition of the
    // string such that both parts have at
    // least k different characters
    static void division_of_string(char[] str, int k)
    {
        // Length of the string
        int n = str.Length;
 
        // To check if the current
        // character is already found
        Dictionary<char, bool> has
            = new Dictionary<char, bool>();
 
        int ans = 0, cnt = 0, i = 0;
 
        // Count number of different
        // characters in the left part
        while (i < n) {
 
            // If current character is not
            // already found, increase cnt by 1
            if (!has.ContainsKey(str[i])) {
                cnt++;
                has.Add(str[i], true);
            }
 
            // If count becomes equal to k, we've
            // got the first part, therefore,
            // store current index and break the loop
            if (cnt == k) {
                ans = i;
                break;
            }
 
            i++;
        }
        // Increment i by 1
        i++;
 
        // Clear the map
        has.Clear();
 
        // Assign cnt as 0
        cnt = 0;
 
        while (i < n) {
 
            // If the current character is not
            // already found, increase cnt by 1
            if (!has.ContainsKey(str[i])) {
                cnt++;
                has.Add(str[i], true);
            }
 
            // If cnt becomes equal to k, the
            // second part also have k different
            // characters so break it
            if (cnt == k) {
                break;
            }
 
            i++;
        }
 
        // If the second part has less than
        // k different characters, then
        // print "Not Possible"
        if (cnt < k) {
            Console.WriteLine("Not possible");
        }
 
        // Otherwise print both parts
        else {
            i = 0;
            while (i <= ans) {
                Console.Write(str[i]);
                i++;
            }
            Console.WriteLine("");
 
            while (i < n) {
                Console.Write(str[i]);
                i++;
            }
            Console.WriteLine("");
        }
 
        Console.WriteLine("");
    }
 
    // Driver code
    public static void Main(String[] args)
    {
        String str = "geeksforgeeks";
        int k = 4;
 
        // Function call
        division_of_string(str.ToCharArray(), k);
    }
}
 
// This code is contributed by Rajput-Ji




<script>
 
    // Javascript implementation of the approach
 
// Function to find the partition of the
// string such that both parts have at
// least k different characters
function division_of_string(str, k)
{
    // Length of the string
    let n = str.length;
   
    // To check if the current
    // character is already found
    let has = new Map();
   
    let ans = 0, cnt = 0, i = 0;
   
    // Count number of different
    // characters in the left part
    while (i < n)
    {
   
        // If current character is not
        // already found, increase cnt by 1
        if (!has.has(str[i]))
        {
            cnt++;
            has.set(str[i], true);
        }
   
        // If count becomes equal to k, we've
        // got the first part, therefore,
        // store current index and break the loop
        if (cnt == k)
        {
            ans = i;
            break;
        }
   
        i++;
    }
     
    //Increment i by 1
    i++;
   
    // Clear the map
    has.clear();
   
    // Assign cnt as 0
    cnt = 0;
   
    while (i < n)
    {
   
        // If the current character is not
        // already found, increase cnt by 1
        if (!has.has(str[i]))
        {
            cnt++;
            has.set(str[i], true);
        }
   
        // If cnt becomes equal to k, the
        // second part also have k different
        // characters so break it
        if (cnt == k)
        {
            break;
        }
   
        i++;
    }
     
    
   
    // If the second part has less than
    // k different characters, then
    // print "Not Possible"
    if (cnt < k)
    {
        document.write("Not possible"  + "<br/>");
    }
   
    // Otherwise print both parts
    else
    {
        i = 0;
        while (i <= ans)
        {
            document.write(str[i]);
            i++;
        }
        document.write("" + "<br/>");
   
        while (i < n)
        {
            document.write(str[i]);
            i++;
        }
        document.write("" + "<br/>");
    }
   
    document.write("" + "<br/>");
}
     
    // Driver code
     
    let str = "geeksforgeeks";
    let k = 4;
   
    // Function call
    division_of_string(str.split(''), k);
   
  // This code is contributed by sanjoy_62.
</script>

Output
geeks
forgeeks








Time Complexity: O(N) where N is the length of the given string.
Auxiliary Space: O(k) where k is the number of distinct characters in the first substring

Efficient Approach:  Instead of using hashmap, we can create a frequency array which keep track of frequency which will be constant and doesnot depend on the size of the string.

Step by step algorithm:




#include <iostream>
#include <cstring>
using namespace std;
 
void division_of_string(string str, int k) {
    int n = str.size();
    int left = 0, right = 0, mid = -1;
    int freq[26];
    memset(freq, 0, sizeof(freq));
 
    // find the first substring with k distinct characters
    while (right < n && k > 0) {
        if (freq[str[right]-'a'] == 0) {
            k--;
        }
        freq[str[right]-'a']++;
        right++;
    }
 
    if (k > 0) {
        cout << "Not possible" << endl;
        return;
    }
 
    mid = right - 1;
 
    // move left and right pointers to find the second substring
    while (left < mid && freq[str[left]-'a'] > 1) {
        freq[str[left]-'a']--;
        left++;
    }
 
    cout << str.substr(0, mid+1) << endl << str.substr(mid+1) << endl;
}
 
int main() {
    string str = "geeksforgeeks";
    int k = 4;
 
    division_of_string(str, k);
 
    return 0;
}




// Java implementation of the approach
 
import java.util.HashMap;
 
public class GFG {
    public static void divisionOfString(String str, int k) {
        int n = str.length();
        int left = 0, right = 0, mid = -1;
        int[] freq = new int[26]; // Array to store the frequency of characters (a-z)
        HashMap<Character, Integer> charCount = new HashMap<>(); // HashMap to store character frequencies
 
        // find the first substring with k distinct characters
        while (right < n && k > 0) {
            char ch = str.charAt(right);
            if (charCount.getOrDefault(ch, 0) == 0) { // Check if character frequency is 0 (i.e., new character)
                k--;
            }
            charCount.put(ch, charCount.getOrDefault(ch, 0) + 1); // Update character frequency in HashMap
            right++;
        }
 
        if (k > 0) {
            System.out.println("Not possible"); // If k distinct characters are not found, print "Not possible"
            return;
        }
 
        mid = right - 1;
 
        // move left and right pointers to find the second substring
        while (left < mid && charCount.get(str.charAt(left)) > 1) {
            char ch = str.charAt(left);
            charCount.put(ch, charCount.get(ch) - 1); // Decrement character frequency as we move left pointer
            left++;
        }
 
        // Print the two substrings divided based on k distinct characters
        System.out.println(str.substring(0, mid + 1));
        System.out.println(str.substring(mid + 1));
    }
 
    public static void main(String[] args) {
        String str = "geeksforgeeks";
        int k = 4;
 
        divisionOfString(str, k);
    }
}




def GFG(s, k):
    n = len(s)
    left = 0
    right = 0
    mid = -1
    freq = [0] * 26
    # Find the first substring with
    # k distinct characters
    while right < n and k > 0:
        if freq[ord(s[right]) - ord('a')] == 0:
            k -= 1
        freq[ord(s[right]) - ord('a')] += 1
        right += 1
    if k > 0:
        print("Not possible")
        return
    mid = right - 1
    # Move left and right pointers to
    # find the second substring
    while left < mid and freq[ord(s[left]) - ord('a')] > 1:
        freq[ord(s[left]) - ord('a')] -= 1
        left += 1
    print(s[:mid + 1])
    print(s[mid + 1:])
def main():
    s = "geeksforgeeks"
    k = 4
    GFG(s, k)
if __name__ == "__main__":
    main()




using System;
 
class GFG {
    static void DivisionOfString(string str, int k)
    {
        int n = str.Length;
        int left = 0, right = 0, mid = -1;
        int[] freq = new int[26];
 
        // find the first substring with k distinct
        // characters
        while (right < n && k > 0) {
            if (freq[str[right] - 'a'] == 0) {
                k--;
            }
            freq[str[right] - 'a']++;
            right++;
        }
 
        if (k > 0) {
            Console.WriteLine("Not possible");
            return;
        }
 
        mid = right - 1;
 
        // move left and right pointers to find the second
        // substring
        while (left < mid && freq[str[left] - 'a'] > 1) {
            freq[str[left] - 'a']--;
            left++;
        }
 
        Console.WriteLine(str.Substring(0, mid + 1));
        Console.WriteLine(str.Substring(mid + 1));
    }
 
    static void Main()
    {
        string str = "geeksforgeeks";
        int k = 4;
 
        DivisionOfString(str, k);
    }
}




function divisionOfString(str, k) {
    const n = str.length;
    let left = 0, right = 0, mid = -1;
    const freq = new Array(26).fill(0);
    // Find the first substring with
    // k distinct characters
    while (right < n && k > 0) {
        if (freq[str.charCodeAt(right) - 'a'.charCodeAt()] === 0) {
            k--;
        }
        freq[str.charCodeAt(right) - 'a'.charCodeAt()]++;
        right++;
    }
    if (k > 0) {
        console.log("Not possible");
        return;
    }
    mid = right - 1;
    // Move left and right pointers to
    // find the second substring
    while (left < mid && freq[str.charCodeAt(left) - 'a'.charCodeAt()] > 1) {
        freq[str.charCodeAt(left) - 'a'.charCodeAt()]--;
        left++;
    }
    console.log(str.substring(0, mid + 1));
    console.log(str.substring(mid + 1));
}
const str = "geeksforgeeks";
const k = 4;
divisionOfString(str, k);

Output
geeks
forgeeks








Time complexity: O(n), where n is the length of the string.
Auxiliary Space: O(1), since we are using a fixed-size array of 26 integers to keep track of character frequencies, which is independent of the length of the string.


Article Tags :