Count ways to split a Binary String into three substrings having equal count of zeros

Given binary string str, the task is to count the total number of ways to split the given string into three non-overlapping substrings having the same number of 0s.

Examples:

Input: str = “01010” 
Output:
Explanation: 
The possible splits are: [0, 10, 10], [01, 01, 0], [01, 0, 10], [0, 101, 0]

Input: str = “11111” 
Output: 0

Approach: To solve the problem, the idea is to use the concept of Hashing. Below are the steps to solve the problem:



  1. Iterate over the string and count the total number of zeros and store it in a variable, say total_count.
  2. Use a Hashmap, say map, to store the frequency of cumulative sum of 0s.
  3. Initialize a variable k with total_count/3 which denotes the number of 0 required in each partition.
  4. Initialize variables res and sum to store the number of ways to split the string and cumulative sum of 0s respectively.
  5. Iterate over the given string and increment sum, if the current character is 0.
  6. Increment res by map[k], if sum = 2k and k exist on the map.
  7. Update the frequency of the sum in the map.
  8. Return res at the end.
  9. Return 0, if total_count is not divisible by 3.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation for the above approach
#include<bits/stdc++.h>
using namespace std;
 
// Function to return ways to split
// a string into three  parts
// with the equal number of 0
int count(string s)
{
     
    // Store total count of 0s
    int cnt = 0;
 
    // Count total no. of 0s
    // character in given string
    for(char c : s)
    {
        cnt += c == '0' ? 1 : 0;
    }
 
    // If total count of 0
    // character is not
    // divisible by 3
    if (cnt % 3 != 0)
        return 0;
 
    int res = 0, k = cnt / 3, sum = 0;
 
    // Initialize mp to store
    // frequency of k
    map<int, int> mp;
 
    // Traverse string to find
    // ways to split string
    for(int i = 0; i < s.length(); i++)
    {
         
        // Increment count if 0 appears
        sum += s[i] == '0' ? 1 : 0;
 
        // Increment result if sum equal to
        // 2*k and k exists in mp
        if (sum == 2 * k && mp.find(k) != mp.end() &&
            i < s.length() - 1 && i > 0)
        {
            res += mp[k];
        }
         
        // Insert sum in mp
        mp[sum]++;
    }
     
    // Return result
    return res;
}
 
// Driver Code
int main()
{
     
    // Given string
    string str = "01010";
  
    // Function call
    cout << count(str);
}
 
// This code is contributed by rutvik_56

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation for the above approach
 
import java.util.*;
import java.lang.*;
 
class GFG {
 
    // Function to return ways to split
    // a string into three  parts
    // with the equal number of 0
    static int count(String s)
    {
        // Store total count of 0s
        int cnt = 0;
 
        // Count total no. of 0s
        // character in given string
        for (char c : s.toCharArray()) {
            cnt += c == '0' ? 1 : 0;
        }
 
        // If total count of 0
        // character is not
        // divisible by 3
        if (cnt % 3 != 0)
            return 0;
 
        int res = 0, k = cnt / 3, sum = 0;
 
        // Initialize map to store
        // frequency of k
        Map<Integer, Integer> map = new HashMap<>();
 
        // Traverse string to find
        // ways to split string
        for (int i = 0; i < s.length(); i++) {
 
            // Increment count if 0 appears
            sum += s.charAt(i) == '0' ? 1 : 0;
 
            // Increment result if sum equal to
            // 2*k and k exists in map
            if (sum == 2 * k && map.containsKey(k)
                && i < s.length() - 1 && i > 0) {
                res += map.get(k);
            }
 
            // Insert sum in map
            map.put(sum,
                    map.getOrDefault(sum, 0) + 1);
        }
 
        // Return result
        return res;
    }
    // Driver Code
    public static void main(String[] args)
    {
        // Given string
        String str = "01010";
 
        // Function call
        System.out.println(count(str));
    }
}

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 implementation for
# the above approach
 
# Function to return ways to split
# a string into three  parts
# with the equal number of 0
def count(s):
 
    # Store total count of 0s
    cnt = 0
 
    # Count total no. of 0s
    # character in given string
    for c in s:
        if c == '0':
            cnt += 1
 
    # If total count of 0
    # character is not
    # divisible by 3
    if (cnt % 3 != 0):
        return 0
 
    res = 0
    k = cnt // 3
    sum = 0
 
    # Initialize map to store
    # frequency of k
    mp = {}
 
    # Traverse string to find
    # ways to split string
    for i in range(len(s)):
 
        # Increment count if 0 appears
        if s[i] == '0':
            sum += 1
 
        # Increment result if sum equal to
        # 2*k and k exists in map
        if (sum == 2 * k and k in mp and
            i < len(s) - 1 and i > 0):
            res += mp[k]
 
        # Insert sum in map
        if sum in mp:
            mp[sum] += 1
        else:
            mp[sum] = 1
             
    # Return result
    return res
 
# Driver Code
if __name__ == "__main__":
 
    # Given string
    st = "01010"
 
    # Function call
    print(count(st))
     
# This code is contributed by Chitranayal

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation for the above approach
using System;
using System.Collections.Generic;
 
class GFG{
 
// Function to return ways to split
// a string into three parts
// with the equal number of 0
static int count(String s)
{
     
    // Store total count of 0s
    int cnt = 0;
 
    // Count total no. of 0s
    // character in given string
    foreach(char c in s.ToCharArray())
    {
        cnt += c == '0' ? 1 : 0;
    }
 
    // If total count of 0
    // character is not
    // divisible by 3
    if (cnt % 3 != 0)
        return 0;
 
    int res = 0, k = cnt / 3, sum = 0;
 
    // Initialize map to store
    // frequency of k
    Dictionary<int,
               int> map = new Dictionary<int,
                                         int>();
 
    // Traverse string to find
    // ways to split string
    for(int i = 0; i < s.Length; i++)
    {
         
        // Increment count if 0 appears
        sum += s[i] == '0' ? 1 : 0;
 
        // Increment result if sum equal to
        // 2*k and k exists in map
        if (sum == 2 * k && map.ContainsKey(k) &&
            i < s.Length - 1 && i > 0)
        {
            res += map[k];
        }
 
        // Insert sum in map
        if(map.ContainsKey(sum))
            map[sum] = map[sum] + 1;
        else
            map.Add(sum, 1);
    }
 
    // Return result
    return res;
}
 
// Driver Code
public static void Main(String[] args)
{
     
    // Given string
    String str = "01010";
 
    // Function call
    Console.WriteLine(count(str));
}
}
 
// This code is contributed by Amit Katiyar

chevron_right


Output

4






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

EFFICIENT APPROACH:

In order to split the input string into three parts, only two cuts are needed, which will give three substrings-S1, S2, and S3. Each substring will be having an equal number of 0’s and that will be (total number of 0’s)/3. Now Keep track of the count of the number of 0’s from the beginning of the string. Once the count is equal to (total number of 0’s)/3, make the first cut. Similarly, make the second cut once the count of 0’s equals to the 2*(total number of 1’s)/3.

Algorithm

  1. Count the number of 0’s. If not divisible by 3 then answer=0.
  2. If the count is 0 then each substring will have an equal number of ‘0’s i.e. zero number of ‘0’s. Therefore, the total number of ways to split the given string is the number of combinations of selecting 2 places to split the string out of n-1 places. For the first selection, we have n-1 choices and for the second selection, we have n-2 choices. Hence the total number of combinations is (n-1)*(n-2). Since the selections are identical therefore divide it by factorial of 2. So answer= ((n-1)*(n-2))/2.
  3. Traverse the given string from the beginning and keeping count of the number of ‘0s’ again, if the count reaches the (total number of ‘0s’)/3, we begin to accumulate the number of the ways of the 1st cut; when the count reaches the 2*(total number of ‘0s’)/3, we start to accumulate the number of the ways of the 2nd cut.
  4. The answer is the multiplication of the number of ways of the 1st cut and 2nd cut.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program for above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to calculate
// the number of ways to split
int splitstring(string s)
{
    int n = s.length();
 
    // Calculating the total
    // number of zeros
    int zeros = 0;
    for (int i = 0; i < n; i++)
        if (s[i] == '0')
            zeros++;
 
    // Case1
    // If total count of zeros is not
    // divisible by 3
    if (zeros % 3 != 0)
        return 0;
 
    // Case2
    // if total count of zeros
    // is zero
    if (zeros == 0)
        return ((n - 1) * (n - 2)) / 2;
 
    // Case3
    // General case
 
    // Number of zeros in each substring
    int zerosInEachSubstring = zeros / 3;
 
    // Initialising zero to the number of ways
    // for first and second cut
    int waysOfFirstCut = 0, waysOfSecondCut = 0;
 
    // Initializing the count
    int count = 0;
 
    // Traversing from the begining
    for (int i = 0; i < n; i++)
    {
         
        // Incrementing the count
        // if the element is '0'
        if (s[i] == '0')
            count++;
 
        // Incrementing the ways for the
        // 1st cut if count is equal to
        // zeros required in each substring
        if (count == zerosInEachSubstring)
            waysOfFirstCut++;
 
        // Incrementing the ways for the
        // 2nd cut if count is equal to
        // 2*(zeros required in each substring)
        else if (count == 2 * zerosInEachSubstring)
            waysOfSecondCut++;
    }
 
    // Total number of ways to split is
    // multiplication of ways for the 1st
    // and 2nd cut
    return waysOfFirstCut * waysOfSecondCut;
}
 
// Driver Code
int main()
{
    string s = "01010";
   
    // Function Call
    cout << "The number of ways to split is "
         << splitstring(s) << endl;
}
 
// this code is contributed by Arif

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java program for above approach
import java.util.*;
 
class GFG{
     
// Function to calculate
// the number of ways to split
static int splitstring(String s)
{
    int n = s.length();
 
    // Calculating the total
    // number of zeros
    int zeros = 0;
    for(int i = 0; i < n; i++)
        if (s.charAt(i) == '0')
            zeros++;
 
    // Case1
    // If total count of zeros is not
    // divisible by 3
    if (zeros % 3 != 0)
        return 0;
 
    // Case2
    // if total count of zeros
    // is zero
    if (zeros == 0)
        return ((n - 1) * (n - 2)) / 2;
 
    // Case3
    // General case
 
    // Number of zeros in each substring
    int zerosInEachSubstring = zeros / 3;
 
    // Initialising zero to the number of ways
    // for first and second cut
    int waysOfFirstCut = 0;
    int waysOfSecondCut = 0;
 
    // Initializing the count
    int count = 0;
 
    // Traversing from the begining
    for(int i = 0; i < n; i++)
    {
         
        // Incrementing the count
        // if the element is '0'
        if (s.charAt(i) == '0')
            count++;
 
        // Incrementing the ways for the
        // 1st cut if count is equal to
        // zeros required in each substring
        if (count == zerosInEachSubstring)
            waysOfFirstCut++;
 
        // Incrementing the ways for the
        // 2nd cut if count is equal to
        // 2*(zeros required in each substring)
        else if (count == 2 * zerosInEachSubstring)
            waysOfSecondCut++;
    }
 
    // Total number of ways to split is
    // multiplication of ways for the 1st
    // and 2nd cut
    return waysOfFirstCut * waysOfSecondCut;
}
 
// Driver Code
public static void main(String args[])
{
    String s = "01010";
 
    // Function Call
    System.out.println("The number of " +
                       "ways to split is " +
                       splitstring(s));
}
}
 
// This code is contributed by Stream_Cipher

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 program for above approach
 
# Function to calculate
# the number of ways to split
def splitstring(s):
 
    n = len(s)
 
    # Calculating the total
    # number of zeros
    zeros = 0
    for i in range(n):
        if s[i] == '0':
            zeros += 1
 
    # Case1
    # If total count of zeros is not
    # divisible by 3
    if zeros % 3 != 0:
        return 0
 
    # Case2
    # if total count of zeros
    # is zero
    if zeros == 0:
        return ((n - 1) *
                (n - 2)) // 2
 
    # Case3
    # General case
 
    # Number of zeros in each substring
    zerosInEachSubstring = zeros // 3
 
    # Initialising zero to the number of ways
    # for first and second cut
    waysOfFirstCut, waysOfSecondCut = 0, 0
 
    # Initializing the count
    count = 0
 
    # Traversing from the begining
    for i in range(n):
         
        # Incrementing the count
        # if the element is '0'
        if s[i] == '0':
            count += 1
 
        # Incrementing the ways for the
        # 1st cut if count is equal to
        # zeros required in each substring
        if (count == zerosInEachSubstring):
            waysOfFirstCut += 1
 
        # Incrementing the ways for the
        # 2nd cut if count is equal to
        # 2*(zeros required in each substring)
        elif (count == 2 * zerosInEachSubstring):
            waysOfSecondCut += 1
 
    # Total number of ways to split is
    # multiplication of ways for the 1st
    # and 2nd cut
    return waysOfFirstCut * waysOfSecondCut
 
# Driver code
s = "01010"
 
# Function call
print("The number of ways to split is", splitstring(s))
 
# This code is contributed by divyeshrabadiya07

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program for above approach
using System.Collections.Generic;
using System;
 
class GFG{
     
// Function to calculate
// the number of ways to split
static int splitstring(string s)
{
    int n = s.Length;
 
    // Calculating the total
    // number of zeros
    int zeros = 0;
    for(int i = 0; i < n; i++)
        if (s[i] == '0')
            zeros++;
 
    // Case1
    // If total count of zeros is not
    // divisible by 3
    if (zeros % 3 != 0)
        return 0;
 
    // Case2
    // if total count of zeros
    // is zero
    if (zeros == 0)
        return ((n - 1) * (n - 2)) / 2;
 
    // Case3
    // General case
 
    // Number of zeros in each substring
    int zerosInEachSubstring = zeros / 3;
 
    // Initialising zero to the number of ways
    // for first and second cut
    int waysOfFirstCut = 0;
    int waysOfSecondCut = 0;
 
    // Initializing the count
    int count = 0;
 
    // Traversing from the begining
    for(int i = 0; i < n; i++)
    {
         
        // Incrementing the count
        // if the element is '0'
        if (s[i] == '0')
            count++;
 
        // Incrementing the ways for the
        // 1st cut if count is equal to
        // zeros required in each substring
        if (count == zerosInEachSubstring)
            waysOfFirstCut++;
 
        // Incrementing the ways for the
        // 2nd cut if count is equal to
        // 2*(zeros required in each substring)
        else if (count == 2 * zerosInEachSubstring)
            waysOfSecondCut++;
    }
 
    // Total number of ways to split is
    // multiplication of ways for the 1st
    // and 2nd cut
    return waysOfFirstCut * waysOfSecondCut;
}
 
// Driver Code
public static void Main()
{
    string s = "01010";
 
    // Function call
    Console.WriteLine("The number of ways " +
                      "to split is " +
                      splitstring(s));
}
}
 
// This code is contributed by Stream_Cipher

chevron_right


Output

The number of ways to split is 4







Time Complexity: O(n)

Space Complexity: O(1)

 

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up

Recommended Posts:


Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.