Skip to content
Related Articles

Related Articles

Improve Article

Optimally accommodate 0s and 1s from a Binary String into K buckets

  • Difficulty Level : Hard
  • Last Updated : 27 Jul, 2021

Given a binary string S, consisting of 0’s and 1’s. You have to accommodate the 0’s and 1’s into the K buckets in such a way that the following conditions are satisfied: 

  1. You fill the 0’s and 1’s into the buckets preserving the relative order of 0’s and 1’s. For example, you cannot put S[1] into bucket 2 and S[0] into bucket 1. You have to preserve the original ordering of the binary string.
  2. No bucket should be left empty and no element in the string should be left unaccommodated.
  3. The sum of all the products of (number of 0’s * number of 1’s) for each bucket should be the minimum among all possible accommodation arrangements.

If a solution is not possible, then print -1.

Examples:  

Input: S = "0001", K = 2
Output: 0
We have 3 choices {"0", "001"}, {"00", "01"}, {"000", 1}
First choice, we will get 1*0 + 2*1 = 2
Second choice, we will get 2*0 + 1*1 = 1
Third choice, we will get 3*0 + 0*1 = 0
Out of all the 3 choices, the third choice 
is giving the minimum answer.

Input: S = "0101", K = 1
Output: 1 

Recursive implementation: You have to accommodate binary string into K buckets without disturbing the above conditions. Then simple recursive solution can be made by first filling up i-th bucket (starting from 0) by putting elements from start to N (N = length of binary string) and keep adding count zeroes and ones till start index. For each iteration, if there x zeroes and y ones till start then recur for f(start, K) = x * y + f(start + 1, K – 1) because next accommodation will be made from (start + 1)-th index and remaining buckets will K – 1. 



So, the recursive formula will be – 

F(start, current_bucket) =  |           |
                            |       min |  F(i + 1, next_bucket) + (ones * zeroes in current_bucket)  
                            |           |   
                            | i = start to N

Top-Down Dynamic Approach: 
The recursive relation can be changed to Dynamic Solution by saving the results of different combinations of start and bucket variable into 2-D DP array. We can use the fact that the order of the string should be preserved. You can have a 2-D array saving the states of size [size of string * buckets], where dp[i][j] will tell us minimum value of accommodation till i’th index of the string using j + 1 buckets. Our final answer will be in dp[N-1][K-1]

Below is the implementation of the above approach:  

C++




// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
 
// 2-D dp array saving different states
// dp[i][j] = minimum value of accommodation
// till i'th index of the string
// using j+1 number of buckets.
vector<vector<int> > dp;
 
// Function to find the minimum required
// sum using dynamic programming
int solveUtil(int start, int bucket, string str, int K)
{
    int N = str.size();
 
    // If both start and bucket reached end then
    // return 0 else that arrangement is not possible
    // so return INT_MAX
    if (start == N) {
        if (bucket == K)
            return 0;
        return INT_MAX;
    }
 
    // Corner case
    if (bucket == K)
        return INT_MAX;
 
    // If state if already calculated
    // then return its answer
    if (dp[start][bucket] != -1)
        return dp[start][bucket];
 
    int zeroes = 0;
    int ones = 0;
    int ans = INT_MAX;
 
    // Start filling zeroes and ones which to be accommodated
    // in jth bucket then ans for current arrangement will be
    // ones*zeroes + recur(i+1, bucket+1)
    for (int i = start; i < N; ++i) {
        if (str[i] == '1')
            ones++;
        else
            zeroes++;
 
        if (ones * zeroes > ans)
            break;
 
        int temp = solveUtil(i + 1, bucket + 1, str, K);
 
        // If this arrangement is not possible then
        // don't calculate further
        if (temp != INT_MAX) {
            ans = min(ans, temp + (ones * zeroes));
        }
    }
 
    return dp[start][bucket] = ans;
}
 
// Function to initialize the dp and call
// solveUtil() method to get the answer
int solve(string str, int K)
{
    int N = str.size();
    dp.clear();
    dp.resize(N, vector<int>(K, -1));
 
    // Start with 0-th index and 1 bucket
    int ans = solveUtil(0, 0, str, K);
 
    return ans == INT_MAX ? -1 : ans;
}
 
// Driver code
int main()
{
    string S = "0101";
 
    // K buckets
    int K = 2;
 
    cout << solve(S, K) << endl;
 
    return 0;
}

Java




// Java implementation of the approach
import java.io.*;
import java.util.*;
 
class GFG{
 
// 2-D dp array saving different states
// dp[i][j] = minimum value of accommodation
// till i'th index of the string
// using j+1 number of buckets.
static int[][] dp;
 
// Function to find the minimum required
// sum using dynamic programming
static int solveUtil(int start, int bucket,
                     String str, int K)
{
    int N = str.length();
     
    // If both start and bucket reached end
    // then return 0 else that arrangement
    // is not possible so return INT_MAX
    if (start == N)
    {
        if (bucket == K)
        {
            return 0;
        }
        return Integer.MAX_VALUE;
    }
     
    // Corner case
    if (bucket == K)
    {
        return Integer.MAX_VALUE;
    }
     
    // If state if already calculated
    // then return its answer
    if (dp[start][bucket] != -1)
    {
        return dp[start][bucket];
    }
    int zeroes = 0;
    int ones = 0;
    int ans = Integer.MAX_VALUE;
     
    // Start filling zeroes and ones which to be
    // accommodated in jth bucket then ans for
    // current arrangement will be
    // ones*zeroes + recur(i+1, bucket+1)
    for(int i = start; i < N; ++i)
    {
        if (str.charAt(i) == '1')
        {
            ones++;
        }
        else
        {
            zeroes++;
        }
        if (ones * zeroes > ans)
        {
            break;
        }
        int temp = solveUtil(i + 1, bucket + 1, str, K);
         
        // If this arrangement is not possible then
        // don't calculate further
        if (temp != Integer.MAX_VALUE)
        {
            ans = Math.min(ans, temp + (ones * zeroes));
        }
    }
    return dp[start][bucket] = ans;
}
 
// Function to initialize the dp and call
// solveUtil() method to get the answer
static int solve(String str, int K)
{
    int N = str.length();
    dp = new int[N][K];
     
    for(int[] row : dp)
    {
        Arrays.fill(row, -1);
    }
     
    // Start with 0-th index and 1 bucket
    int ans = solveUtil(0, 0, str, K);
    return ans == Integer.MAX_VALUE ? -1 : ans;
}
 
// Driver code
public static void main(String[] args)
{
    String S = "0101";
     
    // K buckets
    int K = 2;
     
    System.out.println(solve(S, K));
}
}
 
// This code is contributed by rag2127

Python3




# Python3 implementation of the approach
 
# 2-D dp array saving different states
# dp[i][j] = minimum value of accommodation
# till i'th index of the str1ing
# using j+1 number of buckets.
 
# Function to find the minimum required
# sum using dynamic programming
def solveUtil(start, bucket, str1, K,dp):
 
    N = len(str1)
 
    # If both start and bucket reached end then
    # return 0 else that arrangement is not possible
    # so return INT_MAX
    if (start == N) :
        if (bucket == K):
            return 0
        return 10**9
 
 
    # Corner case
    if (bucket == K):
        return 10**9
 
    # If state if already calculated
    # then return its answer
    if (dp[start][bucket] != -1):
        return dp[start][bucket]
 
    zeroes = 0
    ones = 0
    ans = 10**9
 
    # Start filling zeroes and ones which to be accommodated
    # in jth bucket then ans for current arrangement will be
    # ones*zeroes + recur(i+1, bucket+1)
    for i in range(start,N):
        if (str1[i] == '1'):
            ones += 1
        else:
            zeroes += 1
 
        if (ones * zeroes > ans):
            break
 
        temp = solveUtil(i + 1, bucket + 1, str1, K,dp)
 
        # If this arrangement is not possible then
        # don't calculate further
        if (temp != 10**9):
            ans = min(ans, temp + (ones * zeroes))
 
    dp[start][bucket] = ans
 
    return ans
 
 
# Function to initialize the dp and call
# solveUtil() method to get the answer
def solve(str1, K):
 
    N = len(str1)
 
    dp = [[-1 for i in range(K)] for i in range(N)]
 
    # Start with 0-th index and 1 bucket
    ans = solveUtil(0, 0, str1, K,dp)
 
    if ans == 10**9:
        return -1
    else:
        return ans
 
 
# Driver code
 
s = "0101"
S=[i for i in s]
 
# K buckets
K = 2
 
print(solve(S, K))
 
# This code is contributed by mohit kumar 29

C#




// C# implementation of the approach
using System;
class GFG
{
     
    // 2-D dp array saving different states
    // dp[i][j] = minimum value of accommodation
    // till i'th index of the string
    // using j+1 number of buckets.
    static int[,] dp;
      
    // Function to find the minimum required
    // sum using dynamic programming
    static int solveUtil(int start, int bucket,
                         string str, int K)
    {
        int N = str.Length;
          
        // If both start and bucket reached end
        // then return 0 else that arrangement
        // is not possible so return INT_MAX
        if (start == N)
        {
            if (bucket == K)
            {
                return 0;
            }
            return Int32.MaxValue;
        }
          
        // Corner case
        if (bucket == K)
        {
            return Int32.MaxValue;
        }
          
        // If state if already calculated
        // then return its answer
        if (dp[start,bucket] != -1)
        {
            return dp[start, bucket];
        }
        int zeroes = 0;
        int ones = 0;
        int ans = Int32.MaxValue;
          
        // Start filling zeroes and ones which to be
        // accommodated in jth bucket then ans for
        // current arrangement will be
        // ones*zeroes + recur(i+1, bucket+1)
        for(int i = start; i < N; ++i)
        {
            if (str[i] == '1')
            {
                ones++;
            }
            else
            {
                zeroes++;
            }
            if (ones * zeroes > ans)
            {
                break;
            }
            int temp = solveUtil(i + 1, bucket + 1, str, K);
              
            // If this arrangement is not possible then
            // don't calculate further
            if (temp != Int32.MaxValue)
            {
                ans = Math.Min(ans, temp + (ones * zeroes));
            }
        }
        return dp[start, bucket] = ans;
    }
      
    // Function to initialize the dp and call
    // solveUtil() method to get the answer
    static int solve(string str, int K)
    {
        int N = str.Length;
        dp = new int[N, K];       
        for(int i = 0; i < N; i++)
        {
            for(int j = 0; j < K; j++)
            {
                dp[i, j] = -1;
            }
        }
          
        // Start with 0-th index and 1 bucket
        int ans = solveUtil(0, 0, str, K);
        return ans == Int32.MaxValue ? -1 : ans;
    }
 
  // Driver code
  static void Main()
  {
    string S = "0101";
      
    // K buckets
    int K = 2;
      
    Console.WriteLine(solve(S, K));
  }
}
 
// This code is contributed by divyeshrabadiya07.

Javascript




<script>
 
// Javascript implementation of the approach
 
// 2-D dp array saving different states
// dp[i][j] = minimum value of accommodation
// till i'th index of the string
// using j+1 number of buckets.
let dp;
 
// Function to find the minimum required
// sum using dynamic programming
function solveUtil(start, bucket, str, K)
{
    let N = str.length;
      
    // If both start and bucket reached end
    // then return 0 else that arrangement
    // is not possible so return INT_MAX
    if (start == N)
    {
        if (bucket == K)
        {
            return 0;
        }
        return Number.MAX_VALUE;
    }
      
    // Corner case
    if (bucket == K)
    {
        return Number.MAX_VALUE;
    }
      
    // If state if already calculated
    // then return its answer
    if (dp[start][bucket] != -1)
    {
        return dp[start][bucket];
    }
    let zeroes = 0;
    let ones = 0;
    let ans = Number.MAX_VALUE;
      
    // Start filling zeroes and ones which to be
    // accommodated in jth bucket then ans for
    // current arrangement will be
    // ones*zeroes + recur(i+1, bucket+1)
    for(let i = start; i < N; ++i)
    {
        if (str[i] == '1')
        {
            ones++;
        }
        else
        {
            zeroes++;
        }
        if (ones * zeroes > ans)
        {
            break;
        }
        let temp = solveUtil(i + 1, bucket + 1, str, K);
          
        // If this arrangement is not possible then
        // don't calculate further
        if (temp != Number.MAX_VALUE)
        {
            ans = Math.min(ans, temp + (ones * zeroes));
        }
    }
    return dp[start][bucket] = ans;
}
 
// Function to initialize the dp and call
// solveUtil() method to get the answer
function solve(str, K)
{
    let N = str.length;
    dp = new Array(N);
    for(let i = 0; i < N; i++)
    {
        dp[i] = new Array(K);
        for(let j = 0; j < K; j++)
        {
            dp[i][j] = -1;
        }
    }
     
    // Start with 0-th index and 1 bucket
    let ans = solveUtil(0, 0, str, K);
    return ans == Number.MAX_VALUE ? -1 : ans;
}
 
// Driver code
let  S = "0101";
      
// K buckets
let K = 2;
      
document.write(solve(S, K));
 
// This code is contributed by unknown2108
 
</script>
Output: 
2

 

Time Complexity: O(N3
Space Complexity: O(N2)

This solution is still not optimised because it calls the same state a number of times. So, now look into the Optimised Bottom Up DP Approach.

Bottom-Up Dynamic Approach: Let us try to think about the final state first. Here the variables are the number of buckets and the index of the string. Let dp[i][j] be the minimum sum of products for string elements 0 to j-1 and i buckets. Now to define our transition function, we will have to start from the back and consider partition at each possible position k. Hence our transition function looks like:  

dp [i][j] = for all k = 0 to j min(dp[i][k-1] + numberOfZeroes * numberOfOnes)

for i = 0 (single partition) simple count number of 0's and 1's and do the multiplication. 
And if number of buckets is more than string length till now ans is -1 as we cant fill all 
the available buckets.

Below is the implementation of the above approach: 

C++




// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the minimum required
// sum using dynamic programming
int solve(string str, int K)
{
    int n = str.length();
 
    // dp[i][j] = minimum val of accommodation
    // till j'th index of the string
    // using i+1 number of buckets.
    // Final ans will be in dp[n-1][K-1]
    long long dp[K][n];
 
    // Initialise dp with all states as 0
    memset(dp, 0, sizeof dp);
 
    // Corner cases
    if (n < K)
        return -1;
    else if (n == K)
        return 0;
 
    // Filling first row, if only 1 bucket then simple count
    // number of zeros and ones and do the multiplication
    long long zeroes = 0, ones = 0;
 
    for (int i = 0; i < n; i++) {
        if (str[i] == '0')
            zeroes++;
        else
            ones++;
 
        dp[0][i] = ones * zeroes;
    }
 
    for (int s = 1; s < K; s++) {
        for (int i = 0; i < n; i++) {
 
            dp[s][i] = INT_MAX;
 
            ones = 0;
            zeroes = 0;
            for (int k = i; k >= 0; k--) {
                if (str[k] == '0')
                    zeroes++;
                else
                    ones++;
 
                // If k = 0 then this arrangement is not possible
                dp[s][i] = min(dp[s][i],
                               +((k - 1 >= 0)
                                     ? ones * zeroes + dp[s - 1][k - 1]
                                     : INT_MAX));
            }
        }
    }
 
    // If no arrangement is possible then
    // our answer will remain INT_MAX so return -1
    return (dp[K - 1][n - 1] == INT_MAX) ? -1 : dp[K - 1][n - 1];
}
 
// Driver code
int main()
{
    string S = "0101";
 
    // K buckets
    int K = 2;
 
    cout << solve(S, K) << endl;
 
    return 0;
}

Java




// Java implementation of the approach
 
class GFG
{
    // Function to find the minimum required
    // sum using dynamic programming
    static long solve(String str, int K)
    {
        int n = str.length();
     
        // dp[i][j] = minimum val of accommodation
        // till j'th index of the string
        // using i+1 number of buckets.
        // Final ans will be in dp[n-1][K-1]
        long dp[][] = new long[K][n];
     
     
        // Corner cases
        if (n < K)
            return -1;
        else if (n == K)
            return 0;
     
        // Filling first row, if only 1 bucket then simple count
        // number of zeros and ones and do the multiplication
        long zeroes = 0, ones = 0;
     
        for (int i = 0; i < n; i++)
        {
            if (str.charAt(i) == '0')
                zeroes++;
            else
                ones++;
     
            dp[0][i] = ones * zeroes;
        }
     
        for (int s = 1; s < K; s++)
        {
            for (int i = 0; i < n; i++)
            {
     
                dp[s][i] = Integer.MAX_VALUE;
     
                ones = 0;
                zeroes = 0;
                for (int k = i; k >= 0; k--)
                {
                    if (str.charAt(k) == '0')
                        zeroes++;
                    else
                        ones++;
     
                    // If k = 0 then this arrangement is not possible
                    dp[s][i] = Math.min(dp[s][i],
                                +((k - 1 >= 0)
                                        ? ones * zeroes + dp[s - 1][k - 1]
                                        : Integer.MAX_VALUE));
                }
            }
        }
     
        // If no arrangement is possible then
        // our answer will remain INT_MAX so return -1
        return (dp[K - 1][n - 1] == Integer.MAX_VALUE) ? -1 : dp[K - 1][n - 1];
    }
     
    // Driver code
    public static void main (String[] args)
    {
     
        String S = "0101";
     
        // K buckets
        int K = 2;
     
        System.out.println(solve(S, K));
    }
}
 
// This code is contributed by ihritik

Python3




# Python3 implementation of the approach
import sys
 
# Function to find the minimum required
# sum using dynamic programming
def solve(Str, K):
    n = len(Str)
     
    # dp[i][j] = minimum val of accommodation
    # till j'th index of the string
    # using i+1 number of buckets.
    # Final ans will be in dp[n-1][K-1]
    # Initialise dp with all states as 0
    dp = [[0 for i in range(n)] for j in range(K)]
 
    # Corner cases
    if(n < K):
        return -1
    elif(n == K):
        return 0
 
    # Filling first row, if only 1 bucket then simple count
    # number of zeros and ones and do the multiplication
    zeroes = 0
    ones = 0
 
    for i in range(n):
        if(Str[i] == '0'):
            zeroes += 1
        else:
            ones += 1
        dp[0][i] = ones * zeroes
 
    for s in range(1, K):
        for i in range(n):
            dp[s][i] = sys.maxsize
            ones = 0
            zeroes = 0
 
            for k in range(i, -1, -1):
                if(Str[k] == '0'):
                    zeroes += 1
                else:
                    ones += 1
                 
                # If k = 0 then this arrangement
                # is not possible
                temp = 0
                if(k - 1 >= 0):
                    temp = ones * zeroes + dp[s - 1][k - 1]
                else:
                    temp = sys.maxsize
                dp[s][i] = min(dp[s][i], temp)
     
    # If no arrangement is possible then
    # our answer will remain INT_MAX so return -1
    if(dp[K - 1][n - 1] == sys.maxsize):
        return -1
    else:
        return dp[K - 1][n - 1]
       
# Driver code
S = "0101"
 
# K buckets
K = 2
print(solve(S, K))
 
# This code is contributed by avanitrachhadiya2155

C#




// C# implementation of the approach
using System;
 
class GFG
{
    // Function to find the minimum required
    // sum using dynamic programming
    static long solve(string str, int K)
    {
        int n = str.Length;
     
        // dp[i, j] = minimum val of accommodation
        // till j'th index of the string
        // using i+1 number of buckets.
        // Final ans will be in dp[n-1, K-1]
        long [, ] dp = new long[K, n];
     
     
        // Corner cases
        if (n < K)
            return -1;
        else if (n == K)
            return 0;
     
        // Filling first row, if only 1 bucket then simple count
        // number of zeros and ones and do the multiplication
        long zeroes = 0, ones = 0;
     
        for (int i = 0; i < n; i++)
        {
            if (str[i] == '0')
                zeroes++;
            else
                ones++;
     
            dp[0, i] = ones * zeroes;
        }
     
        for (int s = 1; s < K; s++)
        {
            for (int i = 0; i < n; i++)
            {
     
                dp[s, i] = Int32.MaxValue;
     
                ones = 0;
                zeroes = 0;
                for (int k = i; k >= 0; k--)
                {
                    if (str[k] == '0')
                        zeroes++;
                    else
                        ones++;
     
                    // If k = 0 then this arrangement is not possible
                    dp[s, i] = Math.Min(dp[s, i],
                                +((k - 1 >= 0)
                                        ? ones * zeroes + dp[s - 1, k - 1]
                                        : Int32.MaxValue));
                }
            }
        }
     
        // If no arrangement is possible then
        // our answer will remain INT_MAX so return -1
        return (dp[K - 1, n - 1] == Int32.MaxValue) ? -1 : dp[K - 1, n - 1];
    }
     
    // Driver code
    public static void Main (string[] args)
    {
     
        string S = "0101";
     
        // K buckets
        int K = 2;
     
        Console.WriteLine(solve(S, K));
     
    }
         
}
 
// This code is contributed by ihritik

Javascript




<script>
 
// JavaScript implementation of the approach
 
    // Function to find the minimum required
    // sum using dynamic programming
    function solve(str,K)
    {
        let n = str.length;
      
        // dp[i][j] = minimum val of accommodation
        // till j'th index of the string
        // using i+1 number of buckets.
        // Final ans will be in dp[n-1][K-1]
        let dp = new Array(K);
        for(let i=0;i<K;i++)
        {
            dp[i]=new Array(n);
            for(let j=0;j<n;j++)
            {
                dp[i][j]=0;
            }
        }
      
      
        // Corner cases
        if (n < K)
            return -1;
        else if (n == K)
            return 0;
      
        // Filling first row, if only 1 bucket then simple count
        // number of zeros and ones and do the multiplication
        let zeroes = 0, ones = 0;
      
        for (let i = 0; i < n; i++)
        {
            if (str[i] == '0')
                zeroes++;
            else
                ones++;
      
            dp[0][i] = ones * zeroes;
        }
      
        for (let s = 1; s < K; s++)
        {
            for (let i = 0; i < n; i++)
            {
      
                dp[s][i] = Number.MAX_VALUE;
      
                ones = 0;
                zeroes = 0;
                for (let k = i; k >= 0; k--)
                {
                    if (str[k] == '0')
                        zeroes++;
                    else
                        ones++;
      
                    // If k = 0 then this
                    // arrangement is not possible
                    dp[s][i] = Math.min(dp[s][i],
                                +((k - 1 >= 0)
                          ? ones * zeroes + dp[s - 1][k - 1]
                                        : Number.MAX_VALUE));
                }
            }
        }
      
        // If no arrangement is possible then
        // our answer will remain INT_MAX so return -1
        return (dp[K - 1][n - 1] == Number.MAX_VALUE) ?
        -1 : dp[K - 1][n - 1];
    }
     
    // Driver code
    let S = "0101";
    // K buckets
    let K = 2;
 
    document.write(solve(S, K));
 
 
// This code is contributed by patel2127
 
</script>
Output: 
2

 

Time Complexity: O(N3
Space Complexity: O(N2)
 




My Personal Notes arrow_drop_up
Recommended Articles
Page :