Count possible N-digit numbers such that each digit does not appear more than given number of times consecutively

• Difficulty Level : Medium
• Last Updated : 05 Oct, 2021

Given an integer N and an array maxDigit[], the task is to count all the distinct N-digit numbers such that digit i does not appear more than maxDigit[i] times. Since the count can be very large, print it modulo 109 + 7.

Examples:

Input: N = 2, maxDigit[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
Output: 90
Explanation:
Any digit can’t appear more than once consecutively. Therefore, numbers [00, 11, 22, 33, 44, 55, 66, 77, 88, 99] are invalid.
Hence, the total numbers without any restrictions are 10×10 = 100.
Therefore, the count is 100 – 10 = 90.

Input: N = 3, maxDigit[] = {2, 1, 1, 1, 1, 2, 1, 1, 1, 2}
Output: 864

Naive Approach: The simplest approach is to iterate over all the N-digit numbers and count those numbers that satisfy the given conditions. After checking all the numbers, print the total count modulo 109 + 7

Time Complexity: O(N*10N)
Auxiliary Space: O(1)

Efficient Approach: To optimize the above approach, the idea is to use the concept of Digit Dynamic Programming. The DP states for this problem are explained as follows:

• In Digit-DP, the idea is to build a number from left to right by placing a digit [0, 9] at every position. So, to keep track of the current position, it is required to have a position state. This state will have possible values from 0 to (N – 1).
• According to the question, a digit i can’t appear more than maxDigit[i] consecutive times, therefore keep track of the previously filled digit. So, a state previous is required. This state will have possible values from 0 to 9.
• A state count is required which will provide the number of times a digit can appear consecutively. This state will have possible values from 1 to maxDigit[i].

Follow the steps below to solve this problem:

• The first position can have any digit without any restrictions.
• From the second position and onwards, keep a track of the previously filled digit and its given count up to which it can appear consecutively.
• If the same digit appears on the next position, then decrement its count and if this count becomes zero, simply ignore this digit in the next recursive call.
• If a different digit appears on the next position, then update its count according to the given value in maxDigit[].
• At each of the above recursive calls when the resultant number is generated then increment the count for that number.
• After the above steps, print the value of the total count as the result.

Below is the implementation of the above approach:

C++

 // C++ program for the above approach #include using namespace std;   // Macros for modulus #define MOD 1000000007   // DP array for memoization int dp;   // Utility function to count N digit // numbers with digit i not appearing // more than max_digit[i] consecutively int findCountUtil(int N, int maxDigit[],                   int position = 0,                   int previous = 0,                   int count = 1) {         // If number with N digits     // is generated     if (position == N) {         return 1;     }       // Create a reference variable     int& ans = dp[position][previous][count];       // Check if the current state is     // already computed before     if (ans != -1) {         return ans;     }       // Initialize ans as zero     ans = 0;       for (int i = 0; i <= 9; ++i) {           // Check if count of previous         // digit has reached zero or not         if (count == 0 && previous != i) {               // Fill current position             // only with digits that             // are unequal to previous digit             ans = (ans                    + (findCountUtil(N, maxDigit,                                     position + 1, i,                                     maxDigit[i] - 1))                          % MOD)                   % MOD;         }           else if (count != 0) {               // If by placing the same digit             // as previous on the current             // position, decrement count by 1               // Else set the value of count             // for this new digit             // accordingly from max_digit[]             ans = (ans                    + (findCountUtil(                          N, maxDigit, position + 1, i,                          (previous == i && position != 0)                              ? count - 1                              : maxDigit[i] - 1))                          % MOD)                   % MOD;         }     }     return ans; }   // Function to count N digit numbers // with digit i not appearing more // than max_digit[i] consecutive times void findCount(int N, int maxDigit[]) {         // Stores the final count     int ans = findCountUtil(N, maxDigit);       // Print the total count     cout << ans; }   // Driver Code int main() {     int N = 2;     int maxDigit = { 1, 1, 1, 1, 1,                          1, 1, 1, 1, 1 };       // Initialize the dp array with -1     memset(dp, -1, sizeof(dp));       // Function Call     findCount(N, maxDigit);     return 0; }

Java

 // Java program for the above approach  import java.util.*;   class GFG{           // Macros for modulus static int MOD = 1000000007;   // DP array for memoization static int dp[][][] = new int;   // Utility function to count N digit // numbers with digit i not appearing // more than max_digit[i] consecutively static int findCountUtil(int N, int maxDigit[],                          int position,                          int previous,                          int count) {           // If number with N digits     // is generated     if (position == N)     {         return 1;     }       // Create a reference variable     int ans = dp[position][previous][count];       // Check if the current state is     // already computed before     if (ans != -1)     {         return ans;     }       // Initialize ans as zero     ans = 0;       for(int i = 0; i <= 9; ++i)     {                   // Check if count of previous         // digit has reached zero or not         if (count == 0 && previous != i)         {                           // Fill current position             // only with digits that             // are unequal to previous digit             ans = (ans + (findCountUtil(                   N, maxDigit, position + 1, i,                   maxDigit[i] - 1)) % MOD) % MOD;         }           else if (count != 0)         {                           // If by placing the same digit             // as previous on the current             // position, decrement count by 1               // Else set the value of count             // for this new digit             // accordingly from max_digit[]             ans = (ans + (findCountUtil(                   N, maxDigit, position + 1, i,                   (previous == i && position != 0) ?                   count - 1 : maxDigit[i] - 1)) % MOD) % MOD;         }     }           return ans; }   // Function to count N digit numbers // with digit i not appearing more // than max_digit[i] consecutive times static void findCount(int N, int maxDigit[]) {     int position = 0;     int previous = 0;     int count = 1;           // Stores the final count     int ans = findCountUtil(N, maxDigit, position,                             previous, count);       // Print the total count     System.out.println(ans); }   // Driver Code    public static void main (String[] args)    {        int N = 2;     int[] maxDigit = { 1, 1, 1, 1, 1,                        1, 1, 1, 1, 1 };       // Initialize the dp array with -1     // Fill each row with -1.      for(int[][] row : dp)     {         for(int[] rowColumn : row)         {             Arrays.fill(rowColumn, -1);         }     }           // Function Call     findCount(N, maxDigit); } }   // This code is contributed by susmitakundugoaldanga

Python3

 # Python3 program for the above approach # Macros for modulus   # DP array for memoization dp = [[[ -1 for i in range(5005)] for i in range(12) ] for i in range(12)]   # Utility function to count N digit # numbers with digit i not appearing # more than max_digit[i] consecutively def findCountUtil(N, maxDigit, position ,previous ,count):     global dp           # If number with N digits     # is generated     if (position == N):         return 1       # Create a reference variable     ans = dp[position][previous][count]       # Check if the current state is     # already computed before     if (ans != -1):         return ans       # Initialize ans as zero     ans = 0     for i in range(10):           # Check if count of previous         # digit has reached zero or not         if (count == 0 and previous != i):               # Fill current position             # only with digits that             # are unequal to previous digit             ans = (ans + (findCountUtil(N, maxDigit, position + 1, i, maxDigit[i] - 1)) % 1000000007)% 1000000007         elif (count != 0):               # If by placing the same digit             # as previous on the current             # position, decrement count by 1               # Else set the value of count             # for this new digit             # accordingly from max_digit[]             ans = (ans + (findCountUtil(N, maxDigit, position + 1, i, count - 1 if (previous == i and position != 0) else maxDigit[i] - 1)) % 1000000007)% 1000000007       dp[position][previous][count] = ans     return ans   # Function to count N digit numbers # with digit i not appearing more # than max_digit[i] consecutive times def findCount(N, maxDigit):           # Stores the final count     ans = findCountUtil(N, maxDigit, 0, 0, 1)       # Print the total count     print (ans)   # Driver Code if __name__ == '__main__':     N = 2     maxDigit = [1, 1, 1, 1, 1,1, 1, 1, 1, 1]       # Function Call     findCount(N, maxDigit)       # This code is contributed by mohit kumar 29

C#

 // C# program for the above approach  using System; using System.Collections.Generic;     using System; using System.Collections.Generic; public class GFG{           // Macros for modulus static int MOD = 1000000007;   // DP array for memoization static int [,,]dp = new int[5005, 12, 12];   // Utility function to count N digit // numbers with digit i not appearing // more than max_digit[i] consecutively static int findCountUtil(int N, int []maxDigit,                          int position,                          int previous,                          int count) {           // If number with N digits     // is generated     if (position == N)     {         return 1;     }       // Create a reference variable     int ans = dp[position, previous, count];       // Check if the current state is     // already computed before     if (ans != -1)     {         return ans;     }       // Initialize ans as zero     ans = 0;       for(int i = 0; i <= 9; ++i)     {                   // Check if count of previous         // digit has reached zero or not         if (count == 0 && previous != i)         {                           // Fill current position             // only with digits that             // are unequal to previous digit             ans = (ans + (findCountUtil(                   N, maxDigit, position + 1, i,                   maxDigit[i] - 1)) % MOD) % MOD;         }           else if (count != 0)         {                           // If by placing the same digit             // as previous on the current             // position, decrement count by 1               // Else set the value of count             // for this new digit             // accordingly from max_digit[]             ans = (ans + (findCountUtil(                   N, maxDigit, position + 1, i,                   (previous == i && position != 0) ?                   count - 1 : maxDigit[i] - 1)) % MOD) % MOD;         }     }        return ans; }   // Function to count N digit numbers // with digit i not appearing more // than max_digit[i] consecutive times static void findCount(int N, int []maxDigit) {     int position = 0;     int previous = 0;     int count = 1;           // Stores the readonly count     int ans = findCountUtil(N, maxDigit, position,                             previous, count);       // Print the total count     Console.WriteLine(ans); }   // Driver Code    public static void Main(String[] args)    {        int N = 2;     int[] maxDigit = { 1, 1, 1, 1, 1,                        1, 1, 1, 1, 1 };       // Initialize the dp array with -1     // Fill each row with -1.      for(int i = 0; i < dp.GetLength(0); i++)     {         for (int j = 0; j < dp.GetLength(1); j++)         {             for (int k = 0; k < dp.GetLength(2); k++)                 dp[i, j, k] = -1;         }     }           // Function Call     findCount(N, maxDigit); } }   // This code is contributed by 29AjayKumar

Javascript



Output:

90

Time Complexity: O(N*10*10)
Auxiliary Space: O(N*10*10)

My Personal Notes arrow_drop_up
Recommended Articles
Page :