Data structures & algorithms (Beginner to Intermediate)

Free guided path13 chapters99+ problems

Earn badges and level up

Introduction

In this blog, we will discuss a problem based on strings. Strings are a widely asked topic in coding contests among Data Structures and technical interviews. Greedy is an algorithmic paradigm that develops a solution piece by piece, always opting for the next piece that provides the most evident and immediate benefit. We will be using the greedy approach to solve this problem.

Problem Statement

Ninja has given you a binary string, â€˜Sâ€™, and an integer, â€˜Kâ€™. Your task is to find the minimum number of operations required to make all characters 1s in the string, â€˜Sâ€™. In one operation you can flip all the characters of any substring of size â€˜Kâ€™. If it is not possible to make all characters as 1s, then print -1.

Binary String: A binary string is a string that contains only â€˜0â€™ or â€˜1â€™ as characters.

Example

â€˜00101â€™, â€˜10101â€™, â€˜1111â€™, â€˜0000â€™ etc.

Input

00010110 3

Output

3

Explanation

We can convert the given string into all 1s in 3 operations. Operations performed are:

Flip S[0, 2] (string becomes â€˜11110110â€™).

Flip S[4, 6] (string becomes â€˜11111000â€™).

Flip S[5, 7] (string becomes â€˜11111111â€™).

Get the tech career you deserve, faster!

Connect with our expert counsellors to understand how to hack your way to success

User rating 4.7/5

1:1 doubt support

95% placement record

Akash Pal

Senior Software Engineer

326% Hike After Job Bootcamp

Himanshu Gusain

Programmer Analyst

32 LPA After Job Bootcamp

After Job Bootcamp

Approach

We can approach the given coding challenge in a greedy way. Let us focus on any one index in the given binary string, say, IND such that â€˜S[IND]â€™ = â€˜0â€™. We can consider substrings of size â€˜Kâ€™ containing this index â€˜INDâ€™ and flip these substrings to change the character at â€˜S[IND]â€™. The greedy logic is we can maintain a prefix of all 1â€™s and a suffix containing a mix of 0â€™s and 1â€™s yet to be addressed. We iterate from 0 to N - 1 using the variable â€˜INDâ€™. If â€˜S[IND]â€™ = â€˜0â€™, we can flip the next K characters starting from â€˜INDâ€™.

This is the only possible solution to flip the character at index â€˜INDâ€™. It is because all the substrings with â€˜INDâ€™ being the non-first character are already addressed in previous iterations. All those flips before finally ended up with â€˜S[IND]â€™ being â€˜0â€™. Thus the only possible substring left to be considered is the one starting with IND itself.

Algorithm

1. Declare a variable â€˜MIN_OPERATIONSâ€™ to store the minimum number of operations required.

2. Iterate over the string â€˜Sâ€™ and do the following:

a. If S[i] is â€˜0â€™ and there is a substring of length at least â€˜Kâ€™ present in the right (i.e., i + K <= N), then flip all the characters in the substring S[i, i + K].

b. Increment â€˜MIN_OPERATIONSâ€™ as we just performed a flip operation.

3. Then, once again, iterate over the string â€˜Sâ€™ and check if any character â€˜0â€™ is present in the string.

4. If â€˜0â€™ is not present in the modified string, print â€˜MIN_OPERATIONSâ€™; otherwise, print -1.

Implementation in C++

#include <iostream>
using namespace std;
int findMinOperations(string S, int K){
/* Storing the length of Input string */
int N = S.length();
/* To store the minimum number of operations required. */
int minOperations = 0;
/* Iterating over the string S. */
for(int ind=0; ind<N; ind++){
/* If ith character is '0' and there is substring of length K
present on the right side. */
if(!(S[ind] - '0') && ind+K <= N){
/* Then flip the substring s[i, i+k]. */
for(int j=ind; j<ind+K; j++){
if(S[j]-'0') S[j] = '0';
else S[j] = '1';
}
/* Incrementing the answer since we performed a flip. */
minOperations++;
}
}
bool zeroPresent = false;
/* Checking if the string still contains a zero. */
for(int i=0; i<N; i++){
if(S[i] == '0')zeroPresent = true;
}
/* If there still exists a zero then return -1 otherwise return
minimum number of operations required. */
return (zeroPresent ? -1 : minOperations);
}
// Driver function.
int main(){
string S; cin >> S;
int K; cin >> K;
int ans = findMinOperations(S, K);
cout << "Minimum operations required are : ";
cout << ans << "\n\n";
return 0;
}

Input

00010110 3

Output

Minimum operations required are : 3

Program in Python

def minOperations(Str, K, N):
S = list(Str)
# Stores the count of minimum no. of
# operations needed
min = 0
i = 0
# Traversing the string S
for i in range(0, N):
# If the character in S is 0
if (S[i] == '0' and i + K <= N):
# flipping the substrings of
# size K starting from index i
j = i
while(j < i + K):
if (S[j] == '1'):
S[j] = '0'
else:
S[j] = '1'
j += 1
# Increment the minimum
#count of operations
min += 1
# check if string S contains any 0s
temp = 0
for i in range(0, N):
temp += 1
if (S[i] == '0'):
break
# If string S contains only 1's
if (temp == N):
return min
else:
return -1
# Driver Code begins
S = "00010110"
N = len(S) #length of string S
K = 3
ans=minOperations(S, K, N)
print("Minimum operations required are :",ans)

Output

Minimum operations required are : 3

Program in Java

import java.util.Scanner;
public class Minflips {
static int findMinOperations(char S[], int K){
/* Storing the length of Input string */
int N = S.length;
/* To store the minimum number of operations required. */
int minOperations = 0;
/* Iterating over the string S. */
for(int ind=0; ind<N; ind++){
/* If ith character is '0' and there is substring of length K
present on the right side. */
int check=(S[ind] - '0');
if((check == 0) && (ind+K <= N)){
/* Then flip the substring s[i, i+k]. */
for(int j=ind; j<ind+K; j++){
int check_again=(S[j]-'0');
if(check_again>0){
S[j] = '0';
}
else{
S[j] = '1';
}
}
/* Incrementing the answer since we performed a flip. */
minOperations++;
}
}
boolean zeroPresent = false;
/* Checking if the string still contains a zero. */
for(int i=0; i<N; i++){
if(S[i] == '0')zeroPresent = true;
}
/* If there still exists a zero then return -1 otherwise return
minimum number of operations required. */
return (zeroPresent ? -1 : minOperations);
}
public static void main(String[] args) {
try (Scanner sc = new Scanner(System.in)) {
char[] str= sc.next().toCharArray();
int K=sc.nextInt();
// Call function.
int ans = findMinOperations(str, K);
System.out.print("Minimum operations required are : ");
// Print the final answer.
System.out.print(ans);
System.out.println();
System.out.println();
}
}
}

Input

00010110 3

Output

Minimum operations required are : 3

Complexity Analysis

Time Complexity

The time complexity of the above approach is O(N * K), where â€˜Nâ€™ is the size of the binary string and â€˜Kâ€™ is the input parameter.

It is because we are using two nested for loops with â€˜Nâ€™ and â€˜Kâ€™ as limits.

What is the time complexity for the solution to this problem?

The time complexity for the above solution is O(N*K) where N is the size of the string and K is the length of the string that can be flipped at a time

For what value of K will we always get an answer?

If K = 0 then we always get an answer as only a single character has to be flipped every time.

Conclusion

We used a greedy approach in this blog to solve the problem. We solved this problem using the greedy approach with efficient time and space complexity. Questions involving strings are prevalent in interviews. Such questions are generally easier to implement but require keen observation for designing proper solutions.

Hence learning never stops, and there is a lot more to learn.

Want to practice more greedy problems? Check out these blogs: