algorithmoptimizationbinary-string

Reduce binary string to an empty string by removing subsequences with alternative characters


This was a question asked in the coding round for NASDAQ internship.

Program description:

The program takes a binary string as input. We have to successively remove sub-sequences having all characters alternating, till the string is empty. The task was to find the minimum number of steps required to do so.

Example1:
let the string be : 0111001
Removed-0101, Remaining-110
Removed-10 , Remaining-1
Removed-1
No of steps = 3

Example2:
let the string be : 111000111
Removed-101, Remaining-110011
Removed-101, Remaining-101
Removed-101
No of steps = 3

Example3:
let the string be : 11011
Removed-101, Remaining-11
Removed-1 , Remaining-1
Removed-1
No of steps = 3

Example4:
let the string be : 10101
Removed-10101
No of steps = 1

The solution I tried, considered the first character of the binary string as first character for my sub-sequence. Then created a new string, where the next character would be appended if it wasn't part of the alternating sequence. The new string becomes our binary string. In this way, a loop continues till the new string is empty. (somewhat an O(n^2) algorithm). As expected, it gave me a timeout error. Adding a somewhat similar code in C++ to the one I had tried, which was in Java.

    #include<bits/stdc++.h>
    using namespace std;
    
    int main() {
        string str, newStr;
        int len;
        char c;
        int count = 0;
        getline(cin, str);
        len = str.length();
    
        //continue till string is empty
        while(len > 0) {
            len = 0;
            c = str[0];
            for(int i=1; str[i] != '\0';i++) {
                //if alternative characters are found, set as c and avoid that character
                if(c != str[i]) 
                    c = str[i];
                //if next character is not alternate, add the character to newStr
                else {
                    newStr.push_back(str[i]);
                    len++;
                }
            }
            str = newStr;
            newStr = "";
            count++;
        }
        cout<<count<<endl;
        return 0;
    }

I also tried methods like finding the length of the largest sub sequence of same consecutive characters which obviously didn't satisfy every case, like that of example3.

Hope somebody could help me with the most optimized solution for this question. Preferably a code in C, C++ or python. Even the algorithm would do.


Solution

  • We can solve this in O(n) time and O(1) space.

    This isn't about order at all. The actual task, when you think about it, is how to divide the string into the least number of subsequences that consist of alternating characters (where a single is allowed). Just maintain two queues or stacks; one for 1s, the other for 0s, where characters pop their immediate alternate predecessors. Keep a record of how long the queue is at any one time during the iteration (not including the replacement moves).

    Examples:

    (1)

    0111001
    
       queues
    1  1   -
    0  -   0
    0  -   00
    1  1   0
    1  11  -
    1  111 -  <- max 3
    0  11  0
    

    For O(1) space, The queues can just be two numbers representimg the current counts.

    (2)

    111000111
       queues (count of 1s and count of 0s)
    1  1  0
    1  2  0
    1  3  0  <- max 3
    0  2  1
    0  1  2
    0  0  3  <- max 3
    1  1  2
    1  2  1
    1  3  0  <- max 3
    

    (3)

    11011
       queues
    1  1  0
    1  2  0
    0  1  1
    1  2  0
    1  3  0  <- max 3
    

    (4)

    10101
    
       queues
    1  1  0  <- max 1
    0  0  1  <- max 1
    1  1  0  <- max 1
    0  0  1  <- max 1
    1  1  0  <- max 1