Optimally accommodate 0s and 1s from a Binary String into K buckets
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:
- 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.
- No bucket should be left empty and no element in the string should be left unaccommodated.
- 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++
#include <bits/stdc++.h>
using namespace std;
vector<vector< int > > dp;
int solveUtil( int start, int bucket, string str, int K)
{
int N = str.size();
if (start == N) {
if (bucket == K)
return 0;
return INT_MAX;
}
if (bucket == K)
return INT_MAX;
if (dp[start][bucket] != -1)
return dp[start][bucket];
int zeroes = 0;
int ones = 0;
int ans = INT_MAX;
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 (temp != INT_MAX) {
ans = min(ans, temp + (ones * zeroes));
}
}
return dp[start][bucket] = ans;
}
int solve(string str, int K)
{
int N = str.size();
dp.clear();
dp.resize(N, vector< int >(K, -1));
int ans = solveUtil(0, 0, str, K);
return ans == INT_MAX ? -1 : ans;
}
int main()
{
string S = "0101" ;
int K = 2;
cout << solve(S, K) << endl;
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG{
static int [][] dp;
static int solveUtil( int start, int bucket,
String str, int K)
{
int N = str.length();
if (start == N)
{
if (bucket == K)
{
return 0 ;
}
return Integer.MAX_VALUE;
}
if (bucket == K)
{
return Integer.MAX_VALUE;
}
if (dp[start][bucket] != - 1 )
{
return dp[start][bucket];
}
int zeroes = 0 ;
int ones = 0 ;
int ans = Integer.MAX_VALUE;
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 (temp != Integer.MAX_VALUE)
{
ans = Math.min(ans, temp + (ones * zeroes));
}
}
return dp[start][bucket] = ans;
}
static int solve(String str, int K)
{
int N = str.length();
dp = new int [N][K];
for ( int [] row : dp)
{
Arrays.fill(row, - 1 );
}
int ans = solveUtil( 0 , 0 , str, K);
return ans == Integer.MAX_VALUE ? - 1 : ans;
}
public static void main(String[] args)
{
String S = "0101" ;
int K = 2 ;
System.out.println(solve(S, K));
}
}
|
Python3
def solveUtil(start, bucket, str1, K,dp):
N = len (str1)
if (start = = N) :
if (bucket = = K):
return 0
return 10 * * 9
if (bucket = = K):
return 10 * * 9
if (dp[start][bucket] ! = - 1 ):
return dp[start][bucket]
zeroes = 0
ones = 0
ans = 10 * * 9
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 (temp ! = 10 * * 9 ):
ans = min (ans, temp + (ones * zeroes))
dp[start][bucket] = ans
return ans
def solve(str1, K):
N = len (str1)
dp = [[ - 1 for i in range (K)] for i in range (N)]
ans = solveUtil( 0 , 0 , str1, K,dp)
if ans = = 10 * * 9 :
return - 1
else :
return ans
s = "0101"
S = [i for i in s]
K = 2
print (solve(S, K))
|
C#
using System;
class GFG
{
static int [,] dp;
static int solveUtil( int start, int bucket,
string str, int K)
{
int N = str.Length;
if (start == N)
{
if (bucket == K)
{
return 0;
}
return Int32.MaxValue;
}
if (bucket == K)
{
return Int32.MaxValue;
}
if (dp[start,bucket] != -1)
{
return dp[start, bucket];
}
int zeroes = 0;
int ones = 0;
int ans = Int32.MaxValue;
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 (temp != Int32.MaxValue)
{
ans = Math.Min(ans, temp + (ones * zeroes));
}
}
return dp[start, bucket] = ans;
}
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;
}
}
int ans = solveUtil(0, 0, str, K);
return ans == Int32.MaxValue ? -1 : ans;
}
static void Main()
{
string S = "0101" ;
int K = 2;
Console.WriteLine(solve(S, K));
}
}
|
Javascript
<script>
let dp;
function solveUtil(start, bucket, str, K)
{
let N = str.length;
if (start == N)
{
if (bucket == K)
{
return 0;
}
return Number.MAX_VALUE;
}
if (bucket == K)
{
return Number.MAX_VALUE;
}
if (dp[start][bucket] != -1)
{
return dp[start][bucket];
}
let zeroes = 0;
let ones = 0;
let ans = Number.MAX_VALUE;
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 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;
}
}
let ans = solveUtil(0, 0, str, K);
return ans == Number.MAX_VALUE ? -1 : ans;
}
let S = "0101" ;
let K = 2;
document.write(solve(S, K));
</script>
|
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++
#include <bits/stdc++.h>
using namespace std;
int solve(string str, int K)
{
int n = str.length();
long long dp[K][n];
memset (dp, 0, sizeof dp);
if (n < K)
return -1;
else if (n == K)
return 0;
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++;
dp[s][i] = min(dp[s][i],
+((k - 1 >= 0)
? ones * zeroes + dp[s - 1][k - 1]
: INT_MAX));
}
}
}
return (dp[K - 1][n - 1] == INT_MAX) ? -1 : dp[K - 1][n - 1];
}
int main()
{
string S = "0101" ;
int K = 2;
cout << solve(S, K) << endl;
return 0;
}
|
Java
class GFG
{
static long solve(String str, int K)
{
int n = str.length();
long dp[][] = new long [K][n];
if (n < K)
return - 1 ;
else if (n == K)
return 0 ;
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++;
dp[s][i] = Math.min(dp[s][i],
+((k - 1 >= 0 )
? ones * zeroes + dp[s - 1 ][k - 1 ]
: Integer.MAX_VALUE));
}
}
}
return (dp[K - 1 ][n - 1 ] == Integer.MAX_VALUE) ? - 1 : dp[K - 1 ][n - 1 ];
}
public static void main (String[] args)
{
String S = "0101" ;
int K = 2 ;
System.out.println(solve(S, K));
}
}
|
Python3
import sys
def solve( Str , K):
n = len ( Str )
dp = [[ 0 for i in range (n)] for j in range (K)]
if (n < K):
return - 1
elif (n = = K):
return 0
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
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 (dp[K - 1 ][n - 1 ] = = sys.maxsize):
return - 1
else :
return dp[K - 1 ][n - 1 ]
S = "0101"
K = 2
print (solve(S, K))
|
C#
using System;
class GFG
{
static long solve( string str, int K)
{
int n = str.Length;
long [, ] dp = new long [K, n];
if (n < K)
return -1;
else if (n == K)
return 0;
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++;
dp[s, i] = Math.Min(dp[s, i],
+((k - 1 >= 0)
? ones * zeroes + dp[s - 1, k - 1]
: Int32.MaxValue));
}
}
}
return (dp[K - 1, n - 1] == Int32.MaxValue) ? -1 : dp[K - 1, n - 1];
}
public static void Main ( string [] args)
{
string S = "0101" ;
int K = 2;
Console.WriteLine(solve(S, K));
}
}
|
Javascript
<script>
function solve(str,K)
{
let n = str.length;
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;
}
}
if (n < K)
return -1;
else if (n == K)
return 0;
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++;
dp[s][i] = Math.min(dp[s][i],
+((k - 1 >= 0)
? ones * zeroes + dp[s - 1][k - 1]
: Number.MAX_VALUE));
}
}
}
return (dp[K - 1][n - 1] == Number.MAX_VALUE) ?
-1 : dp[K - 1][n - 1];
}
let S = "0101" ;
let K = 2;
document.write(solve(S, K));
</script>
|
Time Complexity: O(N3)
Space Complexity: O(N2)
Efficient approach : Space optimization
In previous approach the current value dp[s][i] is only depend upon the current and previous row values of DP. So to optimize the space complexity we use a single 1D array to store the computations.
Implementation steps:
- Create a 1D vector dp of size n.
- Set corner cases and base case by initializing the values of DP .
- Create 2 values zeros and ones to store count.
- Now iterate over subproblems by the help of nested loop and get the current value from previous computations.
- At last return the answer if exists in dp[n – 1] else return -1.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
int solve(string str, int K)
{
int n = str.length();
vector< long long > dp(n);
if (n < K)
return -1;
else if (n == K)
return 0;
long long zeroes = 0, ones = 0;
for ( int i = 0; i < n; i++) {
if (str[i] == '0' )
zeroes++;
else
ones++;
dp[i] = ones * zeroes;
}
for ( int s = 1; s < K; s++) {
for ( int i = n-1; i >= 0; i--) {
dp[i] = INT_MAX;
ones = 0;
zeroes = 0;
for ( int k = i; k >= 0; k--) {
if (str[k] == '0' )
zeroes++;
else
ones++;
dp[i] = min(dp[i],
+((k - 1 >= 0)
? ones * zeroes + dp[k - 1]
: INT_MAX));
}
}
}
return (dp[n - 1] == INT_MAX) ? -1 : dp[n - 1];
}
int main()
{
string S = "0101" ;
int K = 2;
cout << solve(S, K) << endl;
return 0;
}
|
Java
import java.util.*;
public class Main {
public static int solve(String str, int K) {
int n = str.length();
int [] dp = new int [n];
Arrays.fill(dp, Integer.MAX_VALUE);
if (n < K)
return - 1 ;
else if (n == K)
return 0 ;
long zeroes = 0 , ones = 0 ;
for ( int i = 0 ; i < n; i++) {
if (str.charAt(i) == '0' )
zeroes++;
else
ones++;
dp[i] = ( int ) (ones * zeroes);
}
for ( int s = 1 ; s < K; s++) {
for ( int i = n- 1 ; i >= 0 ; i--) {
ones = 0 ;
zeroes = 0 ;
for ( int k = i; k >= 0 ; k--) {
if (str.charAt(k) == '0' )
zeroes++;
else
ones++;
if (k - 1 >= 0 )
dp[i] = Math.min(dp[i], ( int ) (ones * zeroes + dp[k - 1 ]));
else
dp[i] = Math.min(dp[i], ( int ) (ones * zeroes));
}
}
}
return (dp[n - 1 ] == Integer.MAX_VALUE) ? - 1 : dp[n - 1 ];
}
public static void main(String[] args) {
String S = "0101" ;
int K = 2 ;
System.out.println(solve(S, K));
}
}
|
Python3
import sys
def solve(s, k):
n = len (s)
dp = [ 0 ] * n
if n < k:
return - 1
elif n = = k:
return 0
zeroes, ones = 0 , 0
for i in range (n):
if s[i] = = '0' :
zeroes + = 1
else :
ones + = 1
dp[i] = ones * zeroes
for s_ in range ( 1 , k):
for i in range (n - 1 , - 1 , - 1 ):
dp[i] = sys.maxsize
ones, zeroes = 0 , 0
for k_ in range (i, - 1 , - 1 ):
if s[k_] = = '0' :
zeroes + = 1
else :
ones + = 1
dp[i] = min (dp[i],
((ones * zeroes + dp[k_ - 1 ])
if k_ - 1 > = 0 else sys.maxsize))
return - 1 if dp[n - 1 ] = = sys.maxsize else dp[n - 1 ]
if __name__ = = '__main__' :
S = "0101"
K = 2
print (solve(S, K))
|
C#
using System;
using System.Collections.Generic;
public class GFG {
static int Solve( string str, int K)
{
int n = str.Length;
long [] dp = new long [n];
if (n < K)
return -1;
else if (n == K)
return 0;
long zeroes = 0, ones = 0;
for ( int i = 0; i < n; i++) {
if (str[i] == '0' )
zeroes++;
else
ones++;
dp[i] = ones * zeroes;
}
for ( int s = 1; s < K; s++) {
for ( int i = n - 1; i >= 0; i--) {
dp[i] = int .MaxValue;
ones = 0;
zeroes = 0;
for ( int k = i; k >= 0; k--) {
if (str[k] == '0' )
zeroes++;
else
ones++;
dp[i] = Math.Min(
dp[i],
((k - 1 >= 0)
? ones * zeroes + dp[k - 1]
: int .MaxValue));
}
}
}
return (dp[n - 1] == int .MaxValue) ? -1
: ( int )dp[n - 1];
}
static void Main( string [] args)
{
string S = "0101" ;
int K = 2;
Console.WriteLine(Solve(S, K));
}
}
|
Javascript
function solve(str, K) {
let n = str.length;
let dp = Array(n);
if (n < K)
return -1;
else if (n == K)
return 0;
let zeroes = 0, ones = 0;
for (let i = 0; i < n; i++) {
if (str[i] == '0 ')
zeroes++;
else
ones++;
dp[i] = ones * zeroes;
}
for (let s = 1; s < K; s++) {
for (let i = n-1; i >= 0; i--) {
dp[i] = Number.MAX_VALUE;
ones = 0;
zeroes = 0;
for (let k = i; k >= 0; k--) {
if (str[k] == ' 0')
zeroes++;
else
ones++;
dp[i] = Math.min(dp[i],
+((k - 1 >= 0)
? ones * zeroes + dp[k - 1]
: Number.MAX_VALUE));
}
}
}
return (dp[n - 1] == Number.MAX_VALUE) ? -1 : dp[n - 1];
}
let S = "0101" ;
let K = 2;
console.log(solve(S, K));
|
Output:
2
Time Complexity: O(n*K^2)
Auxiliary Space: O(N)
Last Updated :
13 Sep, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...