Open In App

Count of non-consecutive Ones in Binary range

Last Updated : 14 Oct, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given two positive integers ‘L’ and ‘R‘, the task is to return the number of the integers in the range [L, R] inclusive, whose binary representations do not contain consecutive ones where 0 ≤ l ≤ r ≤ 10^9

Examples:

Input: L = 0, R = 3
Output: 3
Explanation: The 3 numbers are 0(00), 1(01), 2(10) 3(11) is not included as its binary representation contains consecutive ones

Input: L = 5, R = 10
Output: 4
Explanation: The 4 numbers are 5(101), 8(1000), 9(1001), 10(1010)

Solving problem using Digit Dynamic Programming:

If we say G(x) tells the number of such integers between 0 to x (inclusively) without consecutive 1’s in their binary representation, then the number of such integers between L and R can be given by G(R) – G(L-1). This is when Digit DP (Dynamic Programming) comes into action. All such integer counting problems that satisfy the above property can be solved by the digit DP approach.

Intuition:

If we use the Digit DP approach to build all the binary String from the [ 0, R ] range and [0, L-1] range. then return Numbers in [0, R] range – Numbers in [0, L-1] range. So, we have only 2 digits to form the binary number i.e. 1 and 0.

Steps to solve the above approach:

  • The algorithm iterates through each digit position of the binary representation of 10^9 i.e. it’s 32-bit long.
  • It keeps track of the previous digit, whether it’s 0, 1, or an initial state
  • It considers a “tight” flag that determines the upper bound of the current digit based on the previous digits and the given range.
  • It recursively calculates the count of valid integers by considering all possible digits at each position, excluding combinations with consecutive 1s.
  • The algorithm sums up the counts from all recursive calls and memoizes the result for future use.
  • Finally, the algorithm returns the count of valid integers within the given range by subtracting the count of valid integers from the [L, R] range inclusively.

Below is the implementation of the above approach:

C++




// Cpp code for the above approach:
#include <iostream>
#include <cstring>
#include <bitset>
using namespace std;
 
// Function to solve the digit DP problem
long long solve(string str, int idx, int prev, int tight, long long dp[33][3][2]);
 
// Function to compute the count of non-negative integers
// with no consecutive ones in their binary representation
long long digitDP(string str)
{
    long long dp[33][3][2]; // 3D dynamic programming array
    memset(dp, -1, sizeof(dp)); // Initialize all elements to -1
    return solve(str, 0, 2, 1, dp); // Solve the problem using dynamic programming
}
 
// Recursive function to solve the digit DP problem
long long solve(string str, int idx, int prev, int tight, long long dp[33][3][2])
{
    // Base case: If we have reached the end of the string, return 1
    if (idx >= str.length()) {
        return 1LL;
    }
 
    // If the result for the current state is already computed, return it
    if (dp[idx][prev][tight] != -1) {
        return dp[idx][prev][tight];
    }
 
    long long ans = 0;
    int upperBound = (tight == 1 ? str[idx] - '0' : 1); // Determine the upper bound for the current digit based on the "tight" flag
 
    // Iterate through all possible digits from 0 to the upper bound
    for (int dgt = 0; dgt <= upperBound; dgt++) {
        int newTight = (tight == 0 ? 0 : (dgt == upperBound ? 1 : 0)); // Determine the new "tight" flag based on the current digit and the upper bound
 
        // If the previous digit and the current digit are both 1, skip this combination
        if (prev == 1 && dgt == 1) {
            continue;
        }
 
        // Recursively solve for the next digit
        ans += solve(str, idx + 1, dgt, newTight, dp);
    }
 
    // Memoize the result and return it
    return dp[idx][prev][tight] = ans;
}
 
// Function to compute the count of non-negative integers
// with no consecutive ones in their binary representation
long long findIntegers(int l, int r)
{
    if (l == 0) {
        return digitDP(bitset<32>(r).to_string());
    }
 
    l--;
    return digitDP(bitset<32>(r).to_string()) - digitDP(bitset<32>(l).to_string());
}
 
// Driver code
int main()
{
    // Example usage
    cout << findIntegers(0, 3) << endl;
    cout << findIntegers(5, 10) << endl;
    cout << findIntegers(10, 1000000000) << endl;
 
    return 0;
}


Java




// Java code for the above approach:
import java.util.*;
 
class GFG {
    public static long findIntegers(int l, int r)
    {
 
        // Convert the given integer to
        // its binary representation
        if (l == 0) {
            return digitDP(Integer.toBinaryString(r));
        }
 
        l--;
        return digitDP(Integer.toBinaryString(r))
            - digitDP(Integer.toBinaryString(l));
    }
 
    public static long digitDP(String str)
    {
 
        // Create a 3D dynamic programming
        // array
        long[][][] dp = new long[33][3][2];
 
        // Initialize all elements of
        // the array to -1
        for (long[][] ar : dp) {
            for (long[] e : ar) {
                Arrays.fill(e, -1);
            }
        }
 
        // Solve the problem using
        // dynamic programming
        return solve(str, 0, 2, 1, dp);
    }
 
    public static long solve(String str, int idx, int prev,
                             int tight, long[][][] dp)
    {
 
        // Base case: If we have reached
        // the end of the string, return 1
        if (idx >= str.length()) {
            return 1L;
        }
 
        // If the result for the current
        // state is already computed,
        // return it
        if (dp[idx][prev][tight] != -1) {
            return dp[idx][prev][tight];
        }
 
        long ans = 0;
 
        // Determine the upper bound for
        // the current digit based on
        // the "tight" flag
        int upperBound
            = (tight == 1 ? str.charAt(idx) - '0' : 1);
 
        // Iterate through all possible
        // digits from 0 to the upper bound
        for (int dgt = 0; dgt <= upperBound; dgt++) {
 
            // Determine the new "tight"
            // flag based on the current
            // digit and the upper bound
            int newTight
                = (tight == 0
                       ? 0
                       : (dgt == upperBound ? 1 : 0));
 
            // If the previous digit and
            // the current digit are both 1,
            // skip this combination
            if (prev == 1 && dgt == 1) {
                continue;
            }
 
            // Recursively solve for
            // the next digit
            ans += solve(str, idx + 1, dgt, newTight, dp);
        }
 
        // Memoize the result and return it
        return dp[idx][prev][tight] = ans;
    }
 
    // Drivers code
    public static void main(String args[])
    {
        System.out.println(findIntegers(0, 3));
        System.out.println(findIntegers(5, 10));
        System.out.println(findIntegers(10, 1000000000));
    }
}


Python3




# Python3 code to solve the above problem
# Function to solve the digit DP problem
def solve(str, idx, prev, tight, dp):
    # Base case: If we have reached the end of the string, return 1
    if idx >= len(str):
        return 1
 
    # If the result for the current state is already computed, return it
    if dp[idx][prev][tight] != -1:
        return dp[idx][prev][tight]
 
    ans = 0
    upperBound = int(str[idx]) if tight == 1 else 1 # Determine the upper bound for the current digit based on the "tight" flag
 
    # Iterate through all possible digits from 0 to the upper bound
    for dgt in range(upperBound + 1):
        newTight = 0 if (tight == 0) else ( 1 if dgt == upperBound else 0 ) # Determine the new "tight" flag based on the current digit and the upper bound
 
        # If the previous digit and the current digit are both 1, skip this combination
        if prev == 1 and dgt == 1:
            continue
 
        # Recursively solve for the next digit
        ans += solve(str, idx + 1, dgt, newTight, dp)
 
    # Memoize the result and return it
    dp[idx][prev][tight] = ans
    return ans
 
# Function to compute the count of non-negative integers
# with no consecutive ones in their binary representation
def findIntegers(l, r):
    if l == 0:
        return solve(bin(r)[2:], 0, 2, 1, [[[-1 for _ in range(2)] for _ in range(3)] for _ in range(32)])
 
    l -= 1
    return solve(bin(r)[2:], 0, 2, 1, [[[-1 for _ in range(2)] for _ in range(3)] for _ in range(32)]) - solve(bin(l)[2:], 0, 2, 1, [[[-1 for _ in range(2)] for _ in range(3)] for _ in range(32)])
 
# Example usage
print(findIntegers(0, 3))
print(findIntegers(5, 10))
print(findIntegers(10, 1000000000))
 
# This code is contributed by Tapesh(tapeshdua420)


C#




// C# code for the above approach
using System;
 
public class GFG {
    public static long FindIntegers(int l, int r)
    {
        // Convert the given integer to its binary
        // representation
        if (l == 0) {
            return DigitDP(Convert.ToString(r, 2));
        }
 
        l--;
        return DigitDP(Convert.ToString(r, 2))
            - DigitDP(Convert.ToString(l, 2));
    }
 
    public static long DigitDP(string str)
    {
        // Create a 3D dynamic programming array
        long[, , ] dp = new long[33, 3, 2];
 
        // Initialize all elements of the array to -1
        for (int i = 0; i < 33; i++) {
            for (int j = 0; j < 3; j++) {
                for (int k = 0; k < 2; k++) {
                    dp[i, j, k] = -1;
                }
            }
        }
 
        // Solve the problem using dynamic programming
        return Solve(str, 0, 2, 1, dp);
    }
 
    public static long Solve(string str, int idx, int prev,
                             int tight, long[, , ] dp)
    {
        // Base case: If we have reached the end of the
        // string, return 1
        if (idx >= str.Length) {
            return 1L;
        }
 
        // If the result for the current state is already
        // computed, return it
        if (dp[idx, prev, tight] != -1) {
            return dp[idx, prev, tight];
        }
 
        long ans = 0;
 
        // Determine the upper bound for the current digit
        // based on the "tight" flag
        int upperBound
            = (tight == 1) ? (str[idx] - '0') : 1;
 
        // Iterate through all possible digits from 0 to the
        // upper bound
        for (int dgt = 0; dgt <= upperBound; dgt++) {
            // Determine the new "tight" flag based on the
            // current digit and the upper bound
            int newTight
                = (tight == 0)
                      ? 0
                      : ((dgt == upperBound) ? 1 : 0);
 
            // If the previous digit and the current digit
            // are both 1, skip this combination
            if (prev == 1 && dgt == 1) {
                continue;
            }
 
            // Recursively solve for the next digit
            ans += Solve(str, idx + 1, dgt, newTight, dp);
        }
 
        // Memoize the result and return it
        dp[idx, prev, tight] = ans;
        return ans;
    }
 
    // Driver code
    public static void Main(string[] args)
    {
        Console.WriteLine(FindIntegers(0, 3));
        Console.WriteLine(FindIntegers(5, 10));
        Console.WriteLine(FindIntegers(10, 1000000000));
    }
}
 
// This code is contributed by Susobhan Akhuli


Javascript




//JavaScript implementation of the above approach
// Function to solve the digit DP problem
function solve(str, idx, prev, tight, dp) {
    // Base case: If we have reached the end of the string, return 1
    if (idx >= str.length) {
        return 1;
    }
 
    // If the result for the current state is already computed, return it
    if (dp[idx][prev][tight] !== -1) {
        return dp[idx][prev][tight];
    }
 
    let ans = 0;
    let upperBound = tight === 1 ? parseInt(str[idx]) : 1; // Determine the upper bound for the current digit based on the "tight" flag
 
    // Iterate through all possible digits from 0 to the upper bound
    for (let dgt = 0; dgt <= upperBound; dgt++) {
        let newTight = tight === 0 ? 0 : (dgt === upperBound ? 1 : 0); // Determine the new "tight" flag based on the current digit and the upper bound
 
        // If the previous digit and the current digit are both 1, skip this combination
        if (prev === 1 && dgt === 1) {
            continue;
        }
 
        // Recursively solve for the next digit
        ans += solve(str, idx + 1, dgt, newTight, dp);
    }
 
    // Memoize the result and return it
    dp[idx][prev][tight] = ans;
    return ans;
}
 
// Function to compute the count of non-negative integers
// with no consecutive ones in their binary representation
function findIntegers(l, r) {
    if (l === 0) {
        return solve((r).toString(2), 0, 2, 1, Array.from({length: 32}, () => Array.from({length: 3}, () => Array.from({length: 2}, () => -1))));
    }
 
    l -= 1;
    return solve((r).toString(2), 0, 2, 1, Array.from({length: 32}, () => Array.from({length: 3}, () => Array.from({length: 2}, () => -1)))) - solve((l).toString(2), 0, 2, 1, Array.from({length: 32}, () => Array.from({length: 3}, () => Array.from({length: 2}, () => -1))));
}
 
// Example usage
console.log(findIntegers(0, 3));
console.log(findIntegers(5, 10));
console.log(findIntegers(10, 1000000000));
 
// This code is contributed by Sakshi


Output

3
4
2178302







Time Complexity: O(2*idx*prev*tight)
Auxiliary Space: O(idx * prev* tight)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads