Count numbers less than N containing digits from the given set : Digit DP
Given an integer N and set of digits D[], which consists of digits from [1, 9]. The task is to count the numbers possible less than N, whose digits are from the given set of digits.
Examples:
Input: D = [“1”, “4”, “9”], N = 10
Output: 3
Explanation:
There are only 3 numbers possible less than 3 with given set of digits –
1, 4, 9
Input: D[] = {“1”, “3”, “5”, “7”}, N = 100
Output: 20
Explanation:
There are only 20 numbers possible less than 100 with given set of digits –
1, 3, 5, 7, 11, 13, 15, 17, 31, 33, 35, 37, 51, 53, 55, 57, 71, 73, 75, 77.
Naive Approach:Check the digits of all the numbers of range [1, N], If all the digits of a number belong to the given digit set then increment the count by 1.
Efficient Approach: The idea is to use the concept of Digit DP and traverse the given set of digits and generate all the numbers which are strictly less than the given number N. Recursively choose the digit for all the possible position of the number and pass a boolean variable tight to check that by including that digit, the number falls into the given range or not.
Let’s think of the possible state for the DP –
- pos: It tells about the position of the digit to be chosen, such that the number falls into the given range.
- tight: This will help us know about the current digits are restricted or not. If the digits are restricted, then any digit can be chosen from the given set of digits. Otherwise, the digits can be chosen in range [1, N[pos]].
- size: It will tells the number of the digits to be chosen.
Below is the illustration of the recursive function:
- Base Case: The base case for this problem will be when the position of the digit to be chosen is equal to the length of digits to be chosen, then there is only one possible number containing the digits which are chosen till yet.
if (position == countDigits(N))
return 1
- Recursive Case: For generating the number in the given range, use the tight variable to choose the possible digits in range as follows:
- If the value of tight is 0, denotes that by including that digit will give the number less than the given range.
- Otherwise, If the value of tight is 1, denotes that by including that digit, it will give the number greater than the given range. So we can remove all permutations after getting tight value 1 to avoid more number of recursive calls.
- Store the count of the numbers possible after choosing each digit for every position.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int dp[15][2];
string convertToString( int num)
{
stringstream ss;
ss << num;
string s = ss.str();
return s;
}
int calculate( int pos, int tight,
int D[], int sz, string& num)
{
if (pos == num.length())
return 1;
if (dp[pos][tight] != -1)
return dp[pos][tight];
int val = 0;
if (tight == 0) {
for ( int i = 0; i < sz; i++) {
if (D[i] < (num[pos] - '0' )) {
val += calculate(pos + 1,
1, D, sz, num);
}
else if (D[i] == num[pos] - '0' )
val += calculate(pos + 1,
tight, D, sz, num);
}
}
else {
for ( int i = 0; i < sz; i++) {
val += calculate(pos + 1,
tight, D, sz, num);
}
}
return dp[pos][tight] = val;
}
int countNumbers( int D[], int N, int sz)
{
string num = convertToString(N);
int len = num.length();
memset (dp, -1, sizeof (dp));
int ans = calculate(0, 0, D, sz, num);
for ( int i = 1; i < len; i++)
ans += calculate(i, 1, D, sz, num);
return ans;
}
int main()
{
int sz = 3;
int D[sz] = { 1, 4, 9 };
int N = 10;
cout << countNumbers(D, N, sz);
return 0;
}
|
Java
import java.util.*;
class GFG{
static int [][]dp = new int [ 15 ][ 2 ];
static String convertToString( int num)
{
return String.valueOf(num);
}
static int calculate( int pos, int tight,
int D[], int sz, String num)
{
if (pos == num.length())
return 1 ;
if (dp[pos][tight] != - 1 )
return dp[pos][tight];
int val = 0 ;
if (tight == 0 ) {
for ( int i = 0 ; i < sz; i++) {
if (D[i] < (num.charAt(pos) - '0' )) {
val += calculate(pos + 1 ,
1 , D, sz, num);
}
else if (D[i] == num.charAt(pos) - '0' )
val += calculate(pos + 1 ,
tight, D, sz, num);
}
}
else {
for ( int i = 0 ; i < sz; i++) {
val += calculate(pos + 1 ,
tight, D, sz, num);
}
}
return dp[pos][tight] = val;
}
static int countNumbers( int D[], int N, int sz)
{
String num = convertToString(N);
int len = num.length();
for ( int i = 0 ; i < 15 ; i++)
for ( int j = 0 ; j < 2 ; j++)
dp[i][j] = - 1 ;
int ans = calculate( 0 , 0 , D, sz, num);
for ( int i = 1 ; i < len; i++)
ans += calculate(i, 1 , D, sz, num);
return ans;
}
public static void main(String[] args)
{
int sz = 3 ;
int D[] = { 1 , 4 , 9 };
int N = 10 ;
System.out.print(countNumbers(D, N, sz));
}
}
|
Python3
import numpy as np;
dp = np.ones(( 15 , 2 )) * - 1 ;
def convertToString(num) :
return str (num);
def calculate(pos,tight, D, sz, num) :
if (pos = = len (num)):
return 1 ;
if (dp[pos][tight] ! = - 1 ) :
return dp[pos][tight];
val = 0 ;
if (tight = = 0 ) :
for i in range (sz) :
if (D[i] < ( ord (num[pos]) - ord ( '0' ))) :
val + = calculate(pos + 1 , 1 , D, sz, num);
elif (D[i] = = ord (num[pos]) - ord ( '0' )) :
val + = calculate(pos + 1 , tight, D, sz, num);
else :
for i in range (sz) :
val + = calculate(pos + 1 , tight, D, sz, num);
dp[pos][tight] = val;
return dp[pos][tight];
def countNumbers(D, N, sz) :
num = convertToString(N);
length = len (num);
ans = calculate( 0 , 0 , D, sz, num);
for i in range ( 1 ,length) :
ans + = calculate(i, 1 , D, sz, num);
return ans;
if __name__ = = "__main__" :
sz = 3 ;
D = [ 1 , 4 , 9 ];
N = 10 ;
print (countNumbers(D, N, sz));
|
C#
using System;
class GFG{
static int [,]dp = new int [15, 2];
static String convertToString( int num)
{
return String.Join( "" ,num);
}
static int calculate( int pos, int tight,
int []D, int sz, String num)
{
if (pos == num.Length)
return 1;
if (dp[pos,tight] != -1)
return dp[pos,tight];
int val = 0;
if (tight == 0) {
for ( int i = 0; i < sz; i++) {
if (D[i] < (num[pos] - '0' )) {
val += calculate(pos + 1,
1, D, sz, num);
}
else if (D[i] == num[pos] - '0' )
val += calculate(pos + 1,
tight, D, sz, num);
}
}
else {
for ( int i = 0; i < sz; i++) {
val += calculate(pos + 1,
tight, D, sz, num);
}
}
return dp[pos,tight] = val;
}
static int countNumbers( int []D, int N, int sz)
{
String num = convertToString(N);
int len = num.Length;
for ( int i = 0; i < 15; i++)
for ( int j = 0; j < 2; j++)
dp[i,j] = -1;
int ans = calculate(0, 0, D, sz, num);
for ( int i = 1; i < len; i++)
ans += calculate(i, 1, D, sz, num);
return ans;
}
public static void Main(String[] args)
{
int sz = 3;
int []D = { 1, 4, 9 };
int N = 10;
Console.Write(countNumbers(D, N, sz));
}
}
|
Javascript
<script>
var dp = Array.from(Array(15), ()=>Array(2).fill(-1));
function calculate(pos, tight, D, sz, num)
{
if (pos == num.length)
return 1;
if (dp[pos][tight] != -1)
return dp[pos][tight];
var val = 0;
if (tight == 0) {
for ( var i = 0; i < sz; i++) {
if (D[i] < (num[pos] - '0' )) {
val += calculate(pos + 1,
1, D, sz, num);
}
else if (D[i] == num[pos] - '0' )
val += calculate(pos + 1,
tight, D, sz, num);
}
}
else {
for ( var i = 0; i < sz; i++) {
val += calculate(pos + 1,
tight, D, sz, num);
}
}
return dp[pos][tight] = val;
}
function countNumbers(D, N, sz)
{
var num = (N.toString());
var len = num.length;
var ans = calculate(0, 0, D, sz, num);
for ( var i = 1; i < len; i++)
ans += calculate(i, 1, D, sz, num);
return ans;
}
var sz = 3;
var D = [1, 4, 9];
var N = 10;
document.write( countNumbers(D, N, sz));
</script>
|
Time complexity: O(Len(D))
Space complexity: O(12*2)
Last Updated :
29 Jun, 2022
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...