Count numbers in range [L, R] having K consecutive set bits

Given three positive integers L, R, and K, the task is to find the count of numbers in the range [L, R] having K consecutive set bits in their binary representation.

Examples:

Input: L = 4, R = 15, K = 3 
Output:
Explanation: 
Numbers whose binary representation contains K(=3) consecutive set bits are: 
(7)10 = (111)2 
(14)10 = (1110)2 
(15)10 = (1111)2 
Therefore, the required output is 3. 

Input: L = 8, R = 100, K = 3 
Output: 27

Naive Approach: The simplest approach to solve this problem to traverse all possible integers in the range [L, R] and for each number, check if binary representation of the number contains K consecutive 1s or not. If found to be true then print the number.



Time Complexity: O((R – L + 1) * 32)
Auxiliary Space: O(1)

Efficient Approach: The problem can be solved using Digit DP. The idea is to count of numbers having K consecutive 1s in the range [1, R] and subtract the count of the numbers having K consecutive 1s in the range [1, L – 1]. Following are the recurrence relations:

cntN1X(len, cntOne, KOne)             [Tex]= \sum^{1}_{i=0} cntN1X(len + 1, cntOne + i, KOne | (cntOne == K))            [/Tex]

cntN1X(len, cntOne, KOne): Stores the count of numbers in the range [1, X] with the following constraints: 
len = length of binary representation of X
cntOne = Count of consecutive 1s till index len
KOne = Boolean value to check if K consecutive 1s present in X or not. 
 

Follow the steps below to solve the problem:

  • Initialize a 4D array dp[len][cntOne][KOne][tight] to compute and store the values of all subproblems of the above recurrence relation.
  • Finally, return the value of dp[len][cntOne][KOne][tight].

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to implement
// the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the count of numbers in
// range[1, X] having K consecutive set bits
int cntN1X(string str, int len, int K,
    int cntOne, int dp[32][32][2][2],
                bool KOne, bool tight)
{
    // If length of current number is
    // equal to length of string
    if (len == str.length()) {
         
        // If count of consecutive set bits
        // in the current string is >= K
        return (KOne == 1);
    }
     
    // If already computedx
    // equal occurred
    if (dp[len][cntOne][KOne][tight]
                                   != -1) {
        return dp[len][cntOne][KOne][tight];
    }
 
    // If tight is 1, then element present
    // at current index is element present
    // in str at current index. Otherwise, 1.
    int end = tight ? (str[len] - '0'): 1;
     
    // Stores count of numbers whose
    // len th bit is i.
    int res = 0;
     
    // Iterate over all possible
    // value present at current index.
    for(int i = 0; i <= end; i++) {
         
        // Stores count of consecutive 1s
        int temp = (i==1) ? (cntOne + 1): 0;
         
        // Update res.
        res += cntN1X(str, len + 1,
        K, temp, dp, (KOne | (temp == K)),
                    (tight & (i==end)));
    }
     
    return dp[len][cntOne][KOne][tight]
                                    = res;
}
 
 
// Function to find
// binary representation of N
string convertBinary(int N)
{
    // Stores binary
    // representation of N.
    string res;
     
    // Traverse each bit of N.
    while(N) {
         
        // Append current bit
        // in res
        res.push_back(N % 2 + '0');
         
        // Update N.
        N /= 2;
    }
     
    // Append 0 in binary representation
    // Of N
    while(res.length() < 32) {
        res.push_back('0');
    }
     
    // Reverse binary representation of N
    reverse(res.begin(), res.end());
     
    return res;
}
 
// Function to count numbers in
// range[L, R] having K consecutive 1s.
int cntN1XL_R(int L, int R, int K)
{
    // Stores binary representation
    // of (L - 1)
    string Ls = convertBinary(L - 1);
     
    // Stores binary representation
    // of R
    string Rs = convertBinary(R);
     
    // Stores values of overlapping
    // subproblems
    int dp[32][32][2][2];
     
    // Initalize dp[][][][] array.
    memset(dp, -1, sizeof(dp));
     
    // Stores count of numbers from
    // [1, L - 1] having K consecutive 1s
    int resL = cntN1X(Ls, 0, K, 0,
                            dp, 0,1);
     
    // Initalize dp[][][][] array.
    memset(dp, -1, sizeof(dp));
     
     
    // Stores count of numbers from
    // [1, R - 1] having K consecutive 1s
    int resR = cntN1X(Rs, 0, K, 0,
                            dp, 0, 1);
     
    // Return total counts having K
    // consecutive 1s in range[L, R]
    return (resR - resL);
}
 
// Driver Code
int main()
{
    int L = 8;
    int R = 100;
    int K = 3;
    cout<<cntN1XL_R(L, R, K);
     
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java program to implement
// the above approach
import java.util.*;
 
class GFG{
     
// Function to find the count of numbers in
// range[1, X] having K consecutive set bits
public static int cntN1X(String str, int len, int K,
                         int cntOne, int dp[][][][],
                         int KOne, int tight)
{
     
    // If length of current number is
    // equal to length of string
    if (len == str.length())
    {
         
        // If count of consecutive set bits
        // in the current string is >= K
        return (KOne == 1) ? 1 : 0;
    }
 
    // If already computedx
    // equal occurred
    if (dp[len][cntOne][KOne][tight] != -1)
    {
        return dp[len][cntOne][KOne][tight];
    }
 
    // If tight is 1, then element present
    // at current index is element present
    // in str at current index. Otherwise, 1.
    int end = (tight == 1) ?
              (str.charAt(len) - '0') : 1;
 
    // Stores count of numbers whose
    // len th bit is i.
    int res = 0;
 
    // Iterate over all possible
    // value present at current index.
    for(int i = 0; i <= end; i++)
    {
         
        // Stores count of consecutive 1s
        int temp = (i == 1) ? (cntOne + 1) : 0;
 
        // Update res.
        res += cntN1X(str, len + 1, K, temp, dp,
                     (int)(KOne | ((temp == K) ? 1 : 0)),
                     (int)(tight & ((i == end) ? 1 : 0)));
    }
    return dp[len][cntOne][KOne][tight] = res;
}
 
// Function to count numbers in
// range[L, R] having K consecutive 1s.
public static int cntN1XL_R(int L, int R, int K)
{
     
    // Stores binary representation
    // of (L - 1)
    String Ls = Integer.toBinaryString(L - 1);
 
    // Stores binary representation
    // of R
    String Rs = Integer.toBinaryString(R);
 
    // Stores values of overlapping
    // subproblems
    int dp[][][][] = new int[32][32][2][2];
 
    // Initalize dp[][][][] array.
    for(int i[][][] : dp)
        for(int j[][] : i)
            for(int k[] : j)
                Arrays.fill(k, -1);
 
    // Stores count of numbers from
    // [1, L - 1] having K consecutive 1s
    int resL = cntN1X(Ls, 0, K, 0, dp, 0, 1);
 
    // Initalize dp[][][][] array.
    for(int i[][][] : dp)
        for(int j[][] : i)
            for(int k[] : j)
                Arrays.fill(k, -1);
 
    // Stores count of numbers from
    // [1, R - 1] having K consecutive 1s
    int resR = cntN1X(Rs, 0, K, 0, dp, 0, 1);
 
    // Return total counts having K
    // consecutive 1s in range[L, R]
    return (resR - resL);
}
 
// Driver Code
public static void main(String args[])
{
    int L = 8;
    int R = 100;
    int K = 3;
     
    System.out.println(cntN1XL_R(L, R, K));
}
}
 
// This code is contributed by hemanth gadarla

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program to implement
// the above approach
using System;
 
class GFG{
     
// Function to find the count of numbers in
// range[1, X] having K consecutive set bits
public static int cntN1X(String str, int len, int K,
                         int cntOne, int [,,,]dp,
                         int KOne, int tight)
{
     
    // If length of current number is
    // equal to length of string
    if (len == str.Length)
    {
         
        // If count of consecutive set bits
        // in the current string is >= K
        return (KOne == 1) ? 1 : 0;
    }
     
    // If already computedx
    // equal occurred
    if (dp[len, cntOne, KOne, tight] != -1)
    {
        return dp[len, cntOne, KOne, tight];
    }
     
    // If tight is 1, then element present
    // at current index is element present
    // in str at current index. Otherwise, 1.
    int end = (tight == 1) ?
              (str[len] - '0') : 1;
 
    // Stores count of numbers whose
    // len th bit is i.
    int res = 0;
 
    // Iterate over all possible
    // value present at current index.
    for(int i = 0; i <= end; i++)
    {
         
        // Stores count of consecutive 1s
        int temp = (i == 1) ? (cntOne + 1) : 0;
 
        // Update res.
        res += cntN1X(str, len + 1, K, temp, dp,
                     (int)(KOne | ((temp == K) ? 1 : 0)),
                     (int)(tight & ((i == end) ? 1 : 0)));
    }
    return dp[len, cntOne, KOne, tight] = res;
}
 
// Function to count numbers in
// range[L, R] having K consecutive 1s.
public static int cntN1XL_R(int L, int R, int K)
{
     
    // Stores binary representation
    // of (L - 1)
    String Ls = Convert.ToString(L - 1, 2);
 
    // Stores binary representation
    // of R
    String Rs = Convert.ToString(R, 2);
 
    // Stores values of overlapping
    // subproblems
    int [,,,]dp = new int[ 32, 32, 2, 2 ];
 
    // Initalize [,]dp[,] array.
    for(int i = 0; i < 32; i++)
        for(int j = 0; j < 32; j++)
            for(int k = 0; k < 2; k++)
                for(int l = 0; l < 2; l++)
                    dp[i, j, k, l] = -1;
                     
    // Stores count of numbers from
    // [1, L - 1] having K consecutive 1s
    int resL = cntN1X(Ls, 0, K, 0, dp, 0, 1);
     
    // Initalize [,]dp[,] array.
    for(int i = 0; i < 32; i++)
        for(int j = 0; j < 32; j++)
            for(int k = 0; k < 2; k++)
                for(int l = 0; l < 2; l++)
                    dp[i, j, k, l] = -1;
                     
    // Stores count of numbers from
    // [1, R - 1] having K consecutive 1s
    int resR = cntN1X(Rs, 0, K, 0, dp, 0, 1);
     
    // Return total counts having K
    // consecutive 1s in range[L, R]
    return (resR - resL);
}
 
// Driver Code
public static void Main(String []args)
{
    int L = 8;
    int R = 100;
    int K = 3;
     
    Console.WriteLine(cntN1XL_R(L, R, K));
}
}
 
// This code is contributed by gauravrajput1

chevron_right


Output

27







Time complexity: O(322 * 23)
Auxiliary Space: O(322 * 22)

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.