Binary Strings Without Consecutive Ones in Java

An integer 'N' is given. Our task is to find out the total number of binary strings whose size is equal to N such that the strings do not contain consecutive 1's.

Example 1:

Input:

int N = 4

Output: 8

Explanation: For N equal to 4, we have the following binary strings.

0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111, 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111. In these binary strings, only the strings: 0000, 0001, 0010, 0100, 0101, 1000, 1001, and 1010 do not contain consecutive one's, and the count of those strings is 8. Hence the answer is 8.

Example 2:

Input:

int N = 2

Output: 3

Explanation: For N equal to 2, we have the following binary strings.

00, 01, 10, 11. In these binary strings, only 00, 01, & 10 are the strings that do not contain consecutive one's, and the count of those strings is 3. Hence the answer is 3.

Recursive Approach

For the length N, there are 2N possible binary strings. We can do some pruning by using the standard technique of backtracking and can compose only those strings that adhere to the condition given. We will apply simple recursion. For every jth position, there are only two possible bits that have to be placed as we only have to generate binary strings. It is obvious that 1 can only be placed at the jth position when (j - 1)th position does not contain a 1. In simpler words, the number of binary strings that is created by putting 1 at the jth position is the same as the number of binary strings created by putting 0 at the (j - 1)th position. Furthermore, the number of binary strings created by putting 0 at the jth position is the same as the number of binary strings created by putting either a 1 or a 0 at the (j - 1)th position. It forms the perfect recursive approach.

Algorithm

Step 1: Initialize the variable 'sol with the value 0. It stores the final number of the strings that are binary and do not have consecutive 1's.

Step 2: Make two calls to the recursive method. In the first recursive call, pass the 0-bit and the last position as the method arguments, and in the second recursive call, pass the 1-bit and the last position as the method arguments.

  • The first recursive call gives the total number of binary strings that contain 0as their last bit. Also, they do not contain consecutive 1's.
  • The first recursive call gives the total number of binary strings that contain 1as their last bit. Also, they do not contain consecutive 1's.

Step 3: In the recursive method:

  • Define the base condition for terminating the recursion: if the current index 'indx' becomes 0, then return the value 1.
  • If the current bit (that has to be placed) 'currBit' is 0, then do the recursive calls to the previous index, passing 'currBit' as 0in one call and 'currBit' as 1 in the other call.
  • If the current bit (that has to be placed) 'currBit' is 1, then do the solitary recursive call to the previous index passing 'currBit' as 0 and send the value that is sent from this recursive call.

Implementation

The following is the implementation of the above algorithm.

FileName: BinaryString.java

Output:

For the binary strings of size: 4
There are only 8 binary strings that do not have consecutive ones.

For the binary strings of size: 2
There are only 3 binary strings that do not have consecutive ones.

Complexity Analysis: Since the program is using two recursive calls, the time complexity of the program is O(2n), where n is the size of the binary string. The space complexity of the program is O(1), as the program is not using any data structure (excluding the implicit memory consumption during the recursive calls).

The time complexity of the program is too high. Thus, the above solution is not feasible for the larger inputs. Therefore, it is required to do some optimization. The following approach shows the same.

Approach: Using Dynamic Programming (Recursive)

Algorithm

Step 1: Initialize the variable 'sol' with the value 0. It stores the final number of the strings that are binary and do not have consecutive 1's.

Step 2: Create a 2-dimensional array 'dpArr' of the size (2 * N). Assign -1 to all of the elements of the array dpArr. Here, dpArr[p][q] gives the count of the binary strings that has the size equal to p, and has the last bit equal to q. The base condition will be dpArr[0][0] = 1, and dpArr[0][1] = 1.

Step 3: Make two recursive calls inside the method that computes the total number of binary strings that do not contains consecutive one's. In the first recursive call, pass the dpArr, the 0-bit and the last position as the parameters. In the second recursive call pass the dpArr, the 1-bit and the last position as the parameters.

  • The first recursive call gives the total number of binary strings that contain 0as their last bit. Also, they do not contain consecutive 1's.
  • The first recursive call gives the total number of binary strings that contain 1as their last bit. Also, they do not contain consecutive 1's.

Step 3: In the recursive method:

  • Define the base condition for terminating the recursion: if the current index 'indx' becomes 0, then return the value corresponding to the dpArr.
  • If the value of dp[indx][currBit] is not equal to - 1, then it means the value for the index indx and the currBit have already been calculated. Therefore, return the value dp[indx][currBit].
  • If the current bit (that has to be placed) 'currBit' is 0, then do the recursive calls to the previous index passing 'currBit' as 0in one call, and 'currBit' as 1 in the other call. Keep the sum of the answer to these recursive calls in the dpArr.
  • If the current bit (that has to be placed) 'currBit' is 1, then do the solitary recursive call to the previous index passing 'currBit' as 0 and keep the value of this recursive call in the dpArr.

Implementation

The following is the implementation of the above algorithm.

FileName: BinaryString1.java

Output:

For the binary strings of size: 4
There are only 8 binary strings that do not have consecutive ones.

For the binary strings of size: 2
There are only 3 binary strings that do not have consecutive ones.

Complexity Analysis: The array dpArr[] has 2 * N elements, and the value of each element is computed only once. Therefore, the time complexity of the program is O(N) (considering the asymptotic notation). Since there are 2 * N elements in the array dpArr[], therefore, the space complexity of the program is O(N) (again considering the asymptotic notation), where N is the size of the binary string.

We can still do some optimization on the space complexity. Observe the following approach.

Approach: Using Dynamic Programming (Iterative)

Here also, we define dpArr[p][[q] as it gives the count of the binary strings that are of the size 'p' and has the last bit as 'q'. Now we define the transitions as dpArr[p][1] = dpArr[p - 1][0] and dpArr[p][1] = dpArr[p - 1][0] + dpArr[p - 1][1]. Observe that it is not required to keep all of the dp results for the 'p' as 0 to N - 1. Rather that we need to keep the outcome of the previous index that can be accomplished using only two variables. It saves a lot of space and optimizes the linear space complexity to the constant space complexity.

Algorithm

Step 1: Initialize two variables 'prv0 and 'prv1 as 1. The variables prv0 will keep the total number of binary strings that are terminating at the previous index and have the ending bit as 0-bit. Similarly, prv1 keeps the number of binary strings that is terminating at the previous index and have the ending bit as 1-bit. Also, declare two more variables 'curr0' and 'curr1'.

Step 2: Run a for-loop from i 0 to N. Inside the for-loop, do the following:

  • Update the 'curr0' equal to prv0 + prv1.
  • Update 'curr1' equal to prv0.
  • Now, keep 'curr0' in 'prv0' and keep 'curr1' in 'prv1'.

Step 3: In the end, return the sum of 'curr0' and 'curr1'

Implementation

The following is the implementation of the above algorithm.

FileName: BinaryString2.java

Output:

For the binary strings of size: 4
There are only 8 binary strings that do not have consecutive ones.

For the binary strings of size: 2
There are only 3 binary strings that do not have consecutive ones.

Complexity Analysis: Since the program is using a single loop, the time complexity of the program is O(N), where N is the size of the binary string. The space complexity of the program is O(1), i.e., constant.






Latest Courses