Given a positive integer N, the task is to count the number of N-digit numbers whose sum of digits is a prime number.
Examples:
Input: N = 1
Output: 4
Explanation: [2, 3, 5, 7] are single digit numbers whose sum of digits is equal to a prime number.
Input : N = 2
Output : 33
Naive Approach: The simplest approach to solve the given problem is to generate all possible N-digit numbers and count those numbers whose sum of digits is a prime number. After checking for all the numbers, print the value of the count as the resultant total count of numbers.
Time Complexity: O(N *10N)
Efficient Approach: The above approach can also be optimized by using Recursive Dynamic Programming because the above problem has overlapping subproblems and an optimal substructure. Follow the steps below to solve the problem:
- Initialize a global 2D array dp[N+1][N*10] with all values as -1 that stores the result of each recursive call.
- Compute prime numbers upto (N * 10) numbers by using Sieve of Eratosthenes.
- Define a recursive function, say countOfNumbers(index, sum, N) by performing the following steps.
- If the value of the index is N+1,
- If the sum is a prime number, return 1 as a valid N-digit number has been formed.
- Else return 0.
- If the result of the state dp[index][sum] is already computed, return this value dp[index][sum].
- If the current index is 1, then any digit from [1- 9] can be placed, else, [0-9] can be placed.
- After making a valid placement of digits, recursively call the countOfNumbers function for the next index, and sum up all recursive pending results into variable val.
- Store the value of val into the current state of the dp[index][sum] table.
- Return this state’s result val to it’s parent recursive call.
- Print the value returned by the function countOfNumbers(1, 0, N) as the result.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int dp[100][1000];
bool prime[1005];
void SieveOfEratosthenes( int n)
{
prime[0] = prime[1] = false ;
for ( int p = 2; p * p <= n; p++) {
if (prime[p] == true ) {
for ( int i = p * p; i <= n; i += p)
prime[i] = false ;
}
}
}
int countOfNumbers( int index, int sum, int N)
{
if (index == N + 1) {
if (prime[sum] == true ) {
return 1;
}
return 0;
}
int & val = dp[index][sum];
if (val != -1) {
return val;
}
val = 0;
if (index == 1) {
for ( int digit = (N == 1 ? 0 : 1); digit <= 9;
++digit) {
val += countOfNumbers(index + 1, sum + digit,
N);
}
}
else {
for ( int digit = 0; digit <= 9; ++digit) {
val += countOfNumbers(index + 1, sum + digit,
N);
}
}
return val;
}
int main()
{
memset (dp, -1, sizeof dp);
memset (prime, true , sizeof (prime));
SieveOfEratosthenes(1000);
int N = 6;
cout << countOfNumbers(1, 0, N);
return 0;
}
|
Java
import java.util.Arrays;
class GFG{
public static int [][] dp = new int [ 100 ][ 1000 ];
public static boolean [] prime = new boolean [ 1005 ];
public static void SieveOfEratosthenes( int n)
{
prime[ 0 ] = prime[ 1 ] = false ;
for ( int p = 2 ; p * p <= n; p++)
{
if (prime[p] == true )
{
for ( int i = p * p; i <= n; i += p)
prime[i] = false ;
}
}
}
public static int countOfNumbers( int index, int sum,
int N)
{
if (index == N + 1 )
{
if (prime[sum] == true )
{
return 1 ;
}
return 0 ;
}
int val = dp[index][sum];
if (val != - 1 )
{
return val;
}
val = 0 ;
if (index == 1 )
{
for ( int digit = (N == 1 ? 0 : 1 );
digit <= 9 ; ++digit)
{
val += countOfNumbers(index + 1 ,
sum + digit, N);
}
}
else
{
for ( int digit = 0 ; digit <= 9 ; ++digit)
{
val += countOfNumbers(index + 1 ,
sum + digit, N);
}
}
return val;
}
public static void main(String args[])
{
for ( int [] row : dp)
Arrays.fill(row, - 1 );
Arrays.fill(prime, true );
SieveOfEratosthenes( 1000 );
int N = 6 ;
System.out.println(countOfNumbers( 1 , 0 , N));
}
}
|
Python3
dp = [[ - 1 ] * 100 ] * 1000
prime = [ True ] * 1005
def SieveOfEratosthenes(n) :
prime[ 0 ] = prime[ 1 ] = False
p = 2
while (p * p < = n):
if (prime[p] = = True ) :
for i in range (p * p, n + 1 , p) :
prime[i] = False
p + = 1
def countOfNumbers(index, sum , N) :
if (index = = N + 1 ) :
if (prime[ sum ] = = True ) :
return 1
return 0
val = dp[index][ sum ]
if (val ! = - 1 ) :
return val
val = 0
if (index = = 1 ) :
for digit in range ((( 0 , 1 ) [N = = 1 ]) + 1 , 10 , 1 ) :
val + = countOfNumbers(index + 1 , sum + digit, N)
else :
for digit in range ( 0 , 10 , 1 ) :
val + = countOfNumbers(index + 1 , sum + digit, N)
return val
SieveOfEratosthenes( 1000 )
N = 6
print (countOfNumbers( 1 , 0 , N))
|
C#
using System;
public class GFG{
public static int [,] dp = new int [100,1000];
public static bool [] prime = new bool [1005];
public static void SieveOfEratosthenes( int n)
{
prime[0] = prime[1] = false ;
for ( int p = 2; p * p <= n; p++)
{
if (prime[p] == true )
{
for ( int i = p * p; i <= n; i += p)
prime[i] = false ;
}
}
}
public static int countOfNumbers( int index, int sum,
int N)
{
if (index == N + 1)
{
if (prime[sum] == true )
{
return 1;
}
return 0;
}
int val = dp[index,sum];
if (val != -1)
{
return val;
}
val = 0;
if (index == 1)
{
for ( int digit = (N == 1 ? 0 : 1);
digit <= 9; ++digit)
{
val += countOfNumbers(index + 1,
sum + digit, N);
}
}
else
{
for ( int digit = 0; digit <= 9; ++digit)
{
val += countOfNumbers(index + 1,
sum + digit, N);
}
}
return val;
}
public static void Main(String []args)
{
for ( int i = 0; i < 100; i++)
{
for ( int j = 0; j < 1000; j++) {
dp[i,j] = -1;
}
}
for ( int i = 0; i < prime.Length; i++)
prime[i] = true ;
SieveOfEratosthenes(1000);
int N = 6;
Console.WriteLine(countOfNumbers(1, 0, N));
}
}
|
Javascript
<script>
let dp = new Array(100).fill(0).map(() =>
new Array(1000).fill(-1));
let prime = new Array(1005).fill( true );
function SieveOfEratosthenes(n)
{
prime[0] = prime[1] = false ;
for (let p = 2; p * p <= n; p++)
{
if (prime[p] == true )
{
for (let i = p * p; i <= n; i += p)
prime[i] = false ;
}
}
}
function countOfNumbers(index, sum, N)
{
if (index == N + 1)
{
if (prime[sum] == true )
{
return 1;
}
return 0;
}
let val = dp[index][sum];
if (val != -1)
{
return val;
}
val = 0;
if (index == 1)
{
for (let digit = N == 1 ? 0 : 1;
digit <= 9; ++digit)
{
val += countOfNumbers(index + 1,
sum + digit, N);
}
}
else
{
for (let digit = 0; digit <= 9; ++digit)
{
val += countOfNumbers(index + 1,
sum + digit, N);
}
}
return val;
}
SieveOfEratosthenes(1000);
let N = 6;
document.write(countOfNumbers(1, 0, N));
</script>
|
Time Complexity: O(N2 * 10)
Auxiliary Space: O(N2)
Efficient approach : Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.
Steps to solve this problem :
- Create a DP to store the solution of the subproblems and initialize it with 0.
- Initialize the DP with base cases.
- Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in DP.
- Create a variable ans to store the final result and iterate over DP to update ans.
- At last return and print the final solution stored in ans.
Implementation :
C++
#include <bits/stdc++.h>
using namespace std;
void SieveOfEratosthenes( int n, bool prime[]) {
prime[0] = prime[1] = false ;
for ( int p = 2; p * p <= n; p++) {
if (prime[p] == true ) {
for ( int i = p * p; i <= n; i += p)
prime[i] = false ;
}
}
}
int countOfNumbers( int N) {
int dp[N + 1][1000];
memset (dp, 0, sizeof (dp));
bool prime[1005];
memset (prime, true , sizeof (prime));
SieveOfEratosthenes(1000, prime);
for ( int i = 1; i <= 9; i++)
dp[1][i] = 1;
if (N == 1)
dp[1][0] = 1;
for ( int i = 2; i <= N; i++) {
for ( int j = 0; j <= 900; j++) {
for ( int k = 0; k <= 9; k++) {
dp[i][j + k] += dp[i - 1][j];
}
}
}
int ans = 0;
for ( int i = 2; i <= 900; i++) {
if (prime[i])
ans += dp[N][i];
}
return ans;
}
int main() {
int N = 6;
cout << countOfNumbers(N);
return 0;
}
|
Java
import java.util.Arrays;
public class Main
{
public static void SieveOfEratosthenes( int n, boolean [] prime) {
prime[ 0 ] = prime[ 1 ] = false ;
for ( int p = 2 ; p * p <= n; p++) {
if (prime[p] == true ) {
for ( int i = p * p; i <= n; i += p)
prime[i] = false ;
}
}
}
public static int countOfNumbers( int N)
{
int [][] dp = new int [N + 1 ][ 1000 ];
for ( int [] row : dp) {
Arrays.fill(row, 0 );
}
boolean [] prime = new boolean [ 1005 ];
Arrays.fill(prime, true );
SieveOfEratosthenes( 1000 , prime);
for ( int i = 1 ; i <= 9 ; i++)
dp[ 1 ][i] = 1 ;
if (N == 1 )
dp[ 1 ][ 0 ] = 1 ;
for ( int i = 2 ; i <= N; i++) {
for ( int j = 0 ; j <= 900 ; j++) {
for ( int k = 0 ; k <= 9 ; k++) {
dp[i][j + k] += dp[i - 1 ][j];
}
}
}
int ans = 0 ;
for ( int i = 2 ; i <= 900 ; i++) {
if (prime[i])
ans += dp[N][i];
}
return ans;
}
public static void main(String[] args)
{
int N = 6 ;
System.out.println(countOfNumbers(N));
}
}
|
Python3
import math
def SieveOfEratosthenes(n):
prime = [ True ] * (n + 1 )
prime[ 0 ] = prime[ 1 ] = False
for p in range ( 2 , int (math.sqrt(n)) + 1 ):
if prime[p] = = True :
for i in range (p * p, n + 1 , p):
prime[i] = False
return prime
def countOfNumbers(N):
dp = [[ 0 ] * 1000 for i in range (N + 1 )]
prime = [ True ] * 1005
prime = SieveOfEratosthenes( 1000 )
for i in range ( 1 , 10 ):
dp[ 1 ][i] = 1
if N = = 1 :
dp[ 1 ][ 0 ] = 1
for i in range ( 2 , N + 1 ):
for j in range ( 0 , 901 ):
for k in range ( 0 , 10 ):
dp[i][j + k] + = dp[i - 1 ][j]
ans = 0
for i in range ( 2 , 901 ):
if prime[i]:
ans + = dp[N][i]
return ans
if __name__ = = '__main__' :
N = 6
print (countOfNumbers(N))
|
C#
using System;
class GFG {
static void SieveOfEratosthenes( int n, bool [] prime)
{
prime[0] = prime[1] = false ;
for ( int p = 2; p * p <= n; p++) {
if (prime[p] == true ) {
for ( int i = p * p; i <= n; i += p)
prime[i] = false ;
}
}
}
static int CountOfNumbers( int N)
{
int [, ] dp = new int [N + 1, 1000];
Array.Clear(dp, 0, dp.Length);
bool [] prime = new bool [1005];
Array.Fill(prime, true );
SieveOfEratosthenes(1000, prime);
for ( int i = 1; i <= 9; i++)
dp[1, i] = 1;
if (N == 1)
dp[1, 0] = 1;
for ( int i = 2; i <= N; i++) {
for ( int j = 0; j <= 900; j++) {
for ( int k = 0; k <= 9; k++) {
dp[i, j + k] += dp[i - 1, j];
}
}
}
int ans = 0;
for ( int i = 2; i <= 900; i++) {
if (prime[i])
ans += dp[N, i];
}
return ans;
}
public static void Main()
{
int N = 6;
Console.WriteLine(CountOfNumbers(N));
}
}
|
Javascript
function SieveOfEratosthenes(n, prime) {
prime[0] = prime[1] = false ;
for (let p = 2; p * p <= n; p++) {
if (prime[p] === true ) {
for (let i = p * p; i <= n; i += p) {
prime[i] = false ;
}
}
}
}
function countOfNumbers(N) {
const dp = new Array(N + 1).fill( null ).map(() => new Array(1000).fill(0));
const prime = new Array(1005).fill( true );
SieveOfEratosthenes(1000, prime);
for (let i = 1; i <= 9; i++) {
dp[1][i] = 1;
}
if (N === 1) {
dp[1][0] = 1;
}
for (let i = 2; i <= N; i++) {
for (let j = 0; j <= 900; j++) {
for (let k = 0; k <= 9; k++) {
dp[i][j + k] += dp[i - 1][j];
}
}
}
let ans = 0;
for (let i = 2; i <= 900; i++) {
if (prime[i]) {
ans += dp[N][i];
}
}
return ans;
}
const N = 6;
console.log(countOfNumbers(N));
|
Output:
222638
Time Complexity: O(N* 900 * 9)
Auxiliary Space: O(N*1000)
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
30 Nov, 2023
Like Article
Save Article