Count of substrings in a Binary String that contains more 1s than 0s

11 Apr, 2022
Given a binary string s, the task is to calculate the number of such substrings where the count of 1‘s is strictly greater than the count of 0‘s. 
Examples
Input: S = “110011”Output: 11Explanation: Substrings in which the count of 1’s is strictly greater than the count of 0’s are { S[0]}, {S[0], S[1]}, {S[0], S[2]}, {S[0], S[4]}, {S[0], S[5]}, {S[1], S[1]}, {S[1], S[5]}, {S[3], S[5]}, {S[4], S[4]}, {S[4], S[5]}, {S[5], S[5]}.
Input: S = “101”Output: 3
Naive Approach: The simplest approach to solve the problem is to generate all substrings and count the number of 1s and 0s in each substring. Increase the count of those substrings that contain the count of 1s greater than the count of 0s. Finally, print the count obtained.Time Complexity: O(N3)Auxiliary Space: O(1)
Efficient Approach: The above approach can be optimized using Merge Sort Algorithm. Follow the steps below:
Initialize an array, say nums[] of size n, where n is the length of the string.
Traverse the string. If s[i]  == ‘1’, then store 1 in nums[i]. Otherwise, set nums[i] = -1.
Update pref[] to store prefix sum of the array nums[].
Now, the problem reduces to counting the number of pairs(i, j) in the array pref[], where pref[i] < pref[j] and i < j, which is similar to counting inversions in an array from the rear side.
Return the number of inversions of the prefix sum array as the final answer.
Below is the implementation of the above approach.
C++14
Python3
C#
Javascript
Java
// C++ program for the above approach#include <bits/stdc++.h>using namespace std; // Function to merge two partitions// such that the merged array is sortedvoid merge(vector<int>& v, int left,           int mid, int right, int& inversions){    vector<int> temp(right - left + 1);     int i = left;    int j = mid + 1;    int k = 0;    int cnt = 0;     while (i <= mid && j <= right) {        if (v[i] <= v[j]) {            temp[k++] = v[i++];        }        else {            // Counting inversions            inversions += (mid - i + 1);             temp[k++] = v[j++];        }    }     while (i <= mid)        temp[k++] = v[i++];     while (j <= right)        temp[k++] = v[j++];     k = 0;    for (int a = left; a <= right; a++) {        v[a] = temp[k++];    }} // Function to implement merge sortvoid mergeSort(vector<int>& v, int left,               int right, int& inversions){    if (left < right) {        int mid = (left + right) / 2;         mergeSort(v, left, mid, inversions);        mergeSort(v, mid + 1, right, inversions);        merge(v, left, mid, right, inversions);    }} // Function to calculate number of// inversions in a given arrayint CountInversions(vector<int>& v){    int n = v.size();    int inversions = 0;     // Calculate the number of inversions    mergeSort(v, 0, n - 1, inversions);     // Return the number of inversions    return inversions;} // Function to count the number of// substrings that contains more 1s than 0sint getSubsCount(string& input){    int n = input.length();     vector<int> nums(n);     for (int i = 0; i < n; i++) {        nums[i] = input[i] - '0';         if (nums[i] == 0)            nums[i] = -1;    }     // Stores the prefix sum array    vector<int> pref(n);     int sum = 0;     for (int i = 0; i < n; i++) {        sum += nums[i];        pref[i] = sum;    }     int cnt = 0;     // Stores the count of valid substrings    for (int i = 0; i < n; i++) {        if (pref[i] > 0)            cnt++;    }     reverse(pref.begin(), pref.end());     int inversions = CountInversions(pref);     int ans = cnt + inversions;     return ans;} // Driver Codeint main(){     // Given Input    string input = "101";     // Function Call    int ans = getSubsCount(input);     cout << ans << endl;     return 0;}
# python 3 program for the above approach # Function to merge two partitions# such that the merged array is sorteddef merge(v, left,mid, right, inversions):    temp = [0 for i in range(right - left + 1)]     i = left    j = mid + 1    k = 0    cnt = 0     while (i <= mid and j <= right):        if (v[i] <= v[j]):            temp[k] = v[i]            k += 1            i += 1         else:            # Counting inversions            inversions += (mid - i + 1)             temp[k] = v[j]            k += 1            j += 1     while (i <= mid):        temp[k] = v[i]        k += 1        i += 1     while (j <= right):        temp[k] = v[j]        k += 1        j += 1     k = 0    for a in range(left,right+1,1):        v[a] = temp[k]        k += 1 # Function to implement merge sortdef mergeSort(v, left, right,inversions):    if (left < right):        mid = (left + right) // 2         mergeSort(v, left, mid, inversions)        mergeSort(v, mid + 1, right, inversions)        merge(v, left, mid, right, inversions) # Function to calculate number of# inversions in a given arraydef CountInversions(v):    n = len(v)    inversions = 0     # Calculate the number of inversions    mergeSort(v, 0, n - 1, inversions)     # Return the number of inversions    return inversions # Function to count the number of# substrings that contains more 1s than 0sdef getSubsCount(input):    n = len(input)     nums = [0 for i in range(n)]     for i in range(n):        nums[i] = ord(input[i]) - 48         if (nums[i] == 0):            nums[i] = -1     # Stores the prefix sum array    pref = [0 for i in range(n)]     sum = 0     for i in range(n):        sum += nums[i]        pref[i] = sum     cnt = 0     # Stores the count of valid substrings    for i in range(n):        if (pref[i] > 0):            cnt += 1         pref = pref[:-1]     inversions = CountInversions(pref)     ans = cnt + inversions + 1     return ans # Driver Codeif __name__ == '__main__':       # Given Input    input = "101"     # Function Call    ans = getSubsCount(input)    print(ans)         # This code is contributed by ipg2016107.
// C# program of the above approachusing System;using System.Collections.Generic; class GFG{   // Function to merge two partitions  // such that the merged array is sorted  static void merge(int[] v, int left,                    int mid, int right, int inversions)  {    int[] temp = new int[(right - left + 1)];     int i = left;    int j = mid + 1;    int k = 0;     while (i <= mid && j <= right) {      if (v[i] <= v[j]) {        temp[k++] = v[i++];      }      else {        // Counting inversions        inversions += (mid - i + 1);         temp[k++] = v[j++];      }    }     while (i <= mid)      temp[k++] = v[i++];     while (j <= right)      temp[k++] = v[j++];     k = 0;    for (int a = left; a <= right; a++) {      v[a] = temp[k++];    }  }   // Function to implement merge sort  static void mergeSort(int[] v, int left,                        int right, int inversions)  {    if (left < right) {      int mid = (left + right) / 2;       mergeSort(v, left, mid, inversions);      mergeSort(v, mid + 1, right, inversions);      merge(v, left, mid, right, inversions);    }  }   // Function to calculate number of  // inversions in a given array  static int CountInversions(int[] v)  {    int n = v.Length;    int inversions = 0;     // Calculate the number of inversions    mergeSort(v, 0, n - 1, inversions);     // Return the number of inversions    return inversions;  }   // Function to count the number of  // substrings that contains more 1s than 0s  static int getSubsCount(string input)  {    int n = input.Length;     int[] nums = new int[n];     for (int i = 0; i < n; i++) {      nums[i] = input[i] - '0';       if (nums[i] == 0)        nums[i] = -1;    }     // Stores the prefix sum array    int[] pref = new int[n];     int sum = 0;     for (int i = 0; i < n; i++) {      sum += nums[i];      pref[i] = sum;    }     int cnt = 1;     // Stores the count of valid substrings    for (int i = 0; i < n; i++) {      if (pref[i] > 0)        cnt++;    }    Array.Sort(pref);    Array.Reverse(pref);     int inversions = CountInversions(pref);     int ans = cnt + inversions;     return ans;  }   // Driver Code  public static void Main()  {    // Given Input    string input = "101";     // Function Call    int ans = getSubsCount(input);     Console.Write(ans);  }} // This code is contributed by sanjoy_62.
<script>// JavaScript program for the above approachfunction merge(v, left, mid, right, inversions){    var temp = new Array(right - left + 1).fill(0);     var i = left;    var j = mid + 1;    var k = 0;    var cnt = 0;     while (i <= mid && j <= right) {        if (v[i] <= v[j]) {            temp[k] = v[i];            k += 1;            i += 1;        } else {            inversions += (mid - i + 1);            temp[k] = v[j];            k += 1;            j += 1;        }     }     while (i <= mid) {        temp[k] = v[i];        k += 1;        i += 1;    }     while (j <= right) {        temp[k] = v[j];        k += 1;        j += 1;    }    k = 0;    for (var a = left; a <= right; a++) {        v[a] = temp[k];        k += 1;    }} function mergeSort(v, left, right, inversions) {    if (left < right) {        var mid = Math.floor((left + right) / 2);         mergeSort(v, left, mid, inversions);        mergeSort(v, mid + 1, right, inversions);        merge(v, left, mid, right, inversions);    }} function CountInversions(v) {    var n = v.length;    var inversions = 0     // Calculate the number of inversions    mergeSort(v, 0, n - 1, inversions);     return inversions;} function getSubsCount(input) {    var n = input.length;     var nums = new Array(n).fill(0);     for (var i = 0; i < n; i++) {        nums[i] = (input[i]).charCodeAt(0) - 48;         if (nums[i] == 0)            nums[i] = -1;    }     // Stores the prefix sum array    var pref = new Array(n).fill(0);    var sum = 0;     for (var i = 0; i < n; i++) {        sum += nums[i];        pref[i] = sum;    }     var cnt = 0;     // Stores the count of valid substrings    for (var i = 0; i < n; i++) {        if (pref[i] > 0)            cnt += 1;    }     pref.pop();    var inversions = CountInversions(pref);    var ans = cnt + inversions + 1;    return ans;} // Driver Codevar input = "101";var ans = getSubsCount(input);document.write(ans); // This code is contributed by phasing17.</script>
// Java program of the above approach import java.util.*; public class GFG {     // Function to merge two partitions    // such that the merged array is sorted    static void merge(int[] v, int left, int mid, int right,                      int inversions)    {        int[] temp = new int[(right - left + 1)];         int i = left;        int j = mid + 1;        int k = 0;         while ((i <= mid) && (j <= right)) {            if (v[i] <= v[j]) {                temp[k++] = v[i++];            }            else {                // Counting inversions                inversions += (mid - i + 1);                 temp[k++] = v[j++];            }        }         while (i <= mid)            temp[k++] = v[i++];         while (j <= right)            temp[k++] = v[j++];         k = 0;        for (int a = left; a <= right; a++) {            v[a] = temp[k++];        }    }     // Function to implement merge sort    static void mergeSort(int[] v, int left, int right,                          int inversions)    {        if (left < right) {            int mid = (left + right) / 2;             mergeSort(v, left, mid, inversions);            mergeSort(v, mid + 1, right, inversions);            merge(v, left, mid, right, inversions);        }    }     // Function to calculate number of    // inversions in a given array    static int CountInversions(int[] v)    {        int n = v.length;        int inversions = 0;         // Calculate the number of inversions        mergeSort(v, 0, n - 1, inversions);         // Return the number of inversions        return inversions;    }     // Function to count the number of    // substrings that contains more 1s than 0s    static int getSubsCount(String input)    {        int n = input.length();         int[] nums = new int[n];         for (int i = 0; i < n; i++) {            nums[i] = input.charAt(i) - '0';             if (nums[i] == 0)                nums[i] = -1;        }         // Stores the prefix sum array        int[] pref = new int[n];         int sum = 0;         for (int i = 0; i < n; i++) {            sum += nums[i];            pref[i] = sum;        }         int cnt = 1;         // Stores the count of valid substrings        for (int i = 0; i < n; i++) {            if (pref[i] > 0)                cnt++;        }        Arrays.sort(pref);        Collections.reverse(Arrays.asList(pref));         int inversions = CountInversions(pref);         int ans = cnt + inversions;         return ans;    }     // Driver Code    public static void main(String[] args)    {        // Given Input        String input = "101";         // Function Call        int ans = getSubsCount(input);         System.out.println(ans);    }} // This code is contributed by phasing17.
  
3
 
 
Time Complexity: O(NlogN)Auxiliary Space: O(N)
 
ipg2016107
phasing17
sanjoy_62
binary-string
inversion
Merge Sort
substring
Competitive Programming
Divide and Conquer
Strings
Strings
Divide and Conquer
Merge Sort
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.