Open In App

Minimum Operations for a Continuous Segment of Ones

Given two integers N, X, and a binary string S of length N, find the minimum number of operations to make a continuous segment of length X containing all 1s. In one operation, we can select an index i (0<= i < S.length()) and flip all the bits in range [0, i]. Ie. 0 to 1 and 1 to 0.

Examples:



Input: N = 5, S = 10101, X = 3
Output: 2
Explanation:

  • First operation: Select i = 3 and flip the segment [0, 3] of S, then S = 01011
  • Second operation: Select i = 2 and flip the segment [0, 2] of S, then S = 10111

A continuous segment of length X = 3 has been created, which is from range [2, 4] of S = 10111.



Input: N = 7, S = 1011011, X = 5
Output: 2
Explanation:

  • First operation: Select i = 4 and flip the segment [0, 4] of S, then S = 0100111
  • Second operation: Select i = 3 and flip the segment [0, 3] of S, then S = 1011111

A continuous segment of length X = 5 has been created, which is from range [2, 6] of S = 1011111

Approach: The problem can be solved by using the following approach:

The problem can be solved using prefix sum array. Let’s break S into contiguous blocks of zeros and ones. Notice, that for some substring, that starts at position L and ends at position R, the number of flip operations required to make it all ones is related to the number of blocks in it. The idea is to check for every window of size X, starting from the end of the string S. For every window, flip the blocks greedily to get all 1s in the window. Let’s say that some window A of length X consists of Z ‘blocks’. Then, there are 2 cases:

  • If A ends with ‘1’, then we don’t need to flip the last block (as the last block has 1s in it) so the answer is Z-1.
  • A ends with ‘0’, then we need to flip the last block (as the last block has 0s in it) so the answer is Z.

Let’s return to our initial problem. We need to make a window of length X all 1’s. First, let’s create a Prefix sum array of the number of blocks at index i, where pref[i] = number of blocks in the substring S[0…i]. Now iterate over S and for each window, we check the number of blocks in this window and if the window ends with 1, subtract 1. Find the minimum of all such windows to get the answer.

Steps to solve the problem:

Code to implement the approach:




#include <iostream>
#include <string>
#include <algorithm>
#include <climits>
using namespace std;
 
// Method to return the minimum operations required
int min_operations(int N, string S, int X) {
    // Declaring Prefix array
    int pref[N];
 
    // Initializing the first element of the array as 1
    pref[0] = 1;
 
    // Implementing the approach discussed
    for (int i = 1; i < N; i++) {
        pref[i] = pref[i - 1];
        if (S[i] != S[i - 1]) {
            pref[i]++;
        }
    }
 
    int ans = INT_MAX;
     
    // Iterating over every window of size X
    for (int i = 0; i <= N - X; i++) {
        if (S[i + X - 1] == '1') {
            ans = min(ans, pref[i + X - 1] - pref[i]);
        } else {
            ans = min(ans, pref[i + X - 1] - pref[i] + 1);
        }
    }
 
    // Returning the minimum number of operations required
    return ans;
}
 
int main() {
    // Inputs
    int N = 7;
    string S = "1011011";
    int X = 5;
 
    // Printing the minimum operations
    cout << min_operations(N, S, X) << endl;
 
    return 0;
}




// Java code to implement the approach
 
public class GFG {
    // Driver Class
    public static void main(String[] args)
    {
 
        // Inputs
        int N = 7;
        String S = "1011011";
        int X = 5;
 
        // Printing the minimum operations
        System.out.println(min_operations(N, S, X));
    }
 
    // Method to return the minimum
    // operations required
    public static int min_operations(int N, String S, int X)
    {
 
        // declaring Prefix array
        int[] pref = new int[N];
 
        // Initializing first element
        // of array as 1
        pref[0] = 1;
 
        // Implementing the approach discussed
        for (int i = 1; i < N; i++) {
            pref[i] = pref[i - 1];
            if (S.charAt(i) != S.charAt(i - 1))
                pref[i]++;
        }
        int ans = Integer.MAX_VALUE;
        // Iterating over every window
        // of size X
        for (int i = 0; i <= N - X; i++) {
            if (S.charAt(i + X - 1) == '1') {
                ans = Math.min(ans,
                               pref[i + X - 1] - pref[i]);
            }
            else {
                ans = Math.min(ans, pref[i + X - 1]
                                        - pref[i] + 1);
            }
        }
 
        // Returning the minimum number
        // of operations required
        return ans;
    }
}




# Function to return the minimum operations required
def min_operations(N, S, X):
    # Initializing a prefix array
    pref = [0] * N
 
    # Initializing the first element of the array as 1
    pref[0] = 1
 
    # Implementing the approach discussed
    for i in range(1, N):
        pref[i] = pref[i - 1]
        if S[i] != S[i - 1]:
            pref[i] += 1
 
    ans = float('inf')
 
    # Iterating over every window of size X
    for i in range(N - X + 1):
        if S[i + X - 1] == '1':
            ans = min(ans, pref[i + X - 1] - pref[i])
        else:
            ans = min(ans, pref[i + X - 1] - pref[i] + 1)
 
    # Returning the minimum number of operations required
    return ans
 
# Main function
if __name__ == "__main__":
    # Inputs
    N = 7
    S = "1011011"
    X = 5
 
    # Printing the minimum operations
    print(min_operations(N, S, X))




using System;
 
class Program
{
    // Method to return the minimum operations required
    static int MinOperations(int N, string S, int X)
    {
        // Declaring Prefix array
        int[] pref = new int[N];
 
        // Initializing the first element of the array as 1
        pref[0] = 1;
 
        // Implementing the approach discussed
        for (int i = 1; i < N; i++)
        {
            pref[i] = pref[i - 1];
            if (S[i] != S[i - 1])
            {
                pref[i]++;
            }
        }
 
        int ans = int.MaxValue;
 
        // Iterating over every window of size X
        for (int i = 0; i <= N - X; i++)
        {
            if (S[i + X - 1] == '1')
            {
                ans = Math.Min(ans, pref[i + X - 1] - pref[i]);
            }
            else
            {
                ans = Math.Min(ans, pref[i + X - 1] - pref[i] + 1);
            }
        }
 
        // Returning the minimum number of operations required
        return ans;
    }
 
    static void Main(string[] args)
    {
        // Inputs
        int N = 7;
        string S = "1011011";
        int X = 5;
 
        // Printing the minimum operations
        Console.WriteLine(MinOperations(N, S, X));
    }
}




// JavaScript code for the above approach
 
// Function to return the minimum operations required
function minOperations(N, S, X) {
    // Declaring Prefix array
    const pref = new Array(N);
 
    // Initializing the first element of the array as 1
    pref[0] = 1;
 
    // Implementing the approach discussed
    for (let i = 1; i < N; i++) {
        pref[i] = pref[i - 1];
        if (S[i] !== S[i - 1]) {
            pref[i]++;
        }
    }
 
    let ans = Number.MAX_VALUE;
 
    // Iterating over every window of size X
    for (let i = 0; i <= N - X; i++) {
        if (S[i + X - 1] === '1') {
            ans = Math.min(ans, pref[i + X - 1] - pref[i]);
        } else {
            ans = Math.min(ans, pref[i + X - 1] - pref[i] + 1);
        }
    }
 
    // Returning the minimum number of operations required
    return ans;
}
 
// Inputs
const N = 7;
const S = "1011011";
const X = 5;
 
// Printing the minimum operations
console.log(minOperations(N, S, X));
 
// This code is contributed by Abhinav Mahajan (abhinav_m22)

Output
2








Time Complexity: O(N), where N is the length of input string S.
Auxiliary Space: O(N)


Article Tags :