Find the numbers from 1 to N that contains exactly k non-zero digits

Prerequisites: Dynamic Programming, DigitDP
Given two integers N and K. The task is to find the number of integers between 1 and N (inclusive) that contains exactly K non-zero digits when written in base ten.

Examples:  

Input: N = 100, K = 1 
Output: 19 
Explanation: 
The digits with exactly 1 non zero digits between 1 and 100 are: 
1, 2, 3, 4, 5, 6, 7, 8, 9, 
10, 20, 30, 40, 50, 60, 70, 80, 90, 100

Input: N = 25, K = 2 
Output: 14 
Explanation: 
The digits with exactly 2 non zero digits between 1 and 25 are: 
11, 12, 13, 14, 15, 16, 17, 
18, 19, 21, 22, 23, 24, 25 

Approach: It is enough to consider the integers of N digits, by filling the higher digits with 0 if necessary. This problem can be solved by applying the method called digit DP



  • dp[i][0][j] = The higher i digits have already been decided, and there are j non-zero digits, and it has already been determined that it is less than N.
  • dp[i][1][j] = The higher i digits have already been decided, and there are j non-zero digits, and it has not yet been determined that it is less than N.

After computing the above dp, the desired answer is dp[L][0][K] + dp[L][1][K], where L is the number of digits of N

Below is the implementation of the above approach: 

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to find number less than N
// having k non-zero digits
int k_nonzero_numbers(string s, int n, int k)
{
    // Store the memorised values
    int dp[n + 1][2][k + 1];
 
    // Initialise
    for (int i = 0; i <= n; i++)
        for (int j = 0; j < 2; j++)
            for (int x = 0; x <= k; x++)
                dp[i][j][x] = 0;
 
    // Base
    dp[0][0][0] = 1;
 
    // Calculate all states
    // For every state, from numbers 1 to N,
    // the count of numbers which contain exactly j
    // non zero digits is being computed and updated
    // in the dp array.
    for (int i = 0; i < n; ++i) {
        int sm = 0;
        while (sm < 2) {
            for (int j = 0; j < k + 1; ++j) {
                int x = 0;
                while (x <= (sm ? 9 : s[i] - '0')) {
                    dp[i + 1][sm || x < (s[i] - '0')][j + (x > 0)]
                        += dp[i][sm][j];
                    ++x;
                }
            }
            ++sm;
        }
    }
 
    // Return the required answer
    return dp[n][0][k] + dp[n][1][k];
}
 
// Driver code
int main()
{
    string s = "25";
 
    int k = 2;
 
    int n = s.size();
 
    // Function call
    cout << k_nonzero_numbers(s, n, k);
 
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the above approach
class Geeks{
 
// Function to find number less than N
// having k non-zero digits
static int k_nonzero_numbers(String s, int n, int k)
{
     
    // Store the memorised values
    int dp[][][] = new int[n + 1][2][k + 1];
 
    // Initialise
    for(int i = 0; i <= n; i++)
        for(int j = 0; j < 2; j++)
            for(int x = 0; x <= k; x++)
                dp[i][j][x] = 0;
 
    // Base
    dp[0][0][0] = 1;
 
    // Calculate all states
    // For every state, from numbers 1 to N,
    // the count of numbers which contain exactly j
    // non zero digits is being computed and updated
    // in the dp array.
    for(int i = 0; i < n; ++i)
    {
        int sm = 0;
        while (sm < 2)
        {
            for(int j = 0; j < k + 1; ++j)
            {
                int x = 0;
                while (x <= (sm !=
                       0 ? 9 :s.charAt(i) - '0'))
                {
                    if (j + (x > 0 ? 1 : 0) < k + 1)
                    {
                        dp[i + 1][(sm != 0 || x <
                                  (s.charAt(i) - '0')) ?
                                   1 : 0][j + (x > 0 ?
                                   1 : 0)] += dp[i][sm][j];
                    }
                    ++x;
                }
            }
            ++sm;
        }
    }
 
    // Return the required answer
    return dp[n][0][k] + dp[n][1][k];
}
 
// Driver code
public static void main(String[] args)
{
    String s = "25";
 
    int k = 2;
 
    int n = s.length();
 
    // Function call
    System.out.println(k_nonzero_numbers(s, n, k));
}
}
 
// This code is contributed by Rajnis09

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 implementation of the above approach
 
# Function to find number less than N
# having k non-zero digits
def k_nonzero_numbers(s, n, k):
     
    # Store the memorised values
    dp = [[[ 0 for i in range(k + 2)]
               for i in range(2)]
               for i in range(n + 2)]
 
    # Initialise
    for i in range(n + 1):
        for j in range(2):
            for x in range(k + 1):
                dp[i][j][x] = 0
 
    # Base
    dp[0][0][0] = 1
 
    # Calculate all states
    # For every state, from numbers 1 to N,
    # the count of numbers which contain
    # exactly j non zero digits is being
    # computed and updated in the dp array.
    for i in range(n):
        sm = 0
         
        while (sm < 2):
            for j in range(k + 1):
                x = 0
                y = 0
                if sm:
                    y = 9
                else:
                    y = ord(s[i]) - ord('0')
 
                while (x <= y):
                    dp[i + 1][(sm or x < (
                    ord(s[i]) - ord('0')))][j +
                     (x > 0)] += dp[i][sm][j]
                    x += 1
                     
            sm += 1
 
    # Return the required answer
    return dp[n][0][k] + dp[n][1][k]
 
# Driver code
if __name__ == '__main__':
     
    s = "25"
 
    k = 2
 
    n = len(s)
 
    # Function call
    print(k_nonzero_numbers(s, n, k))
 
# This code is contributed by mohit kumar 29

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation of the above approach
using System;
using System.Collections;
 
class GFG{
 
// Function to find number less than N
// having k non-zero digits
static int k_nonzero_numbers(string s, int n,
                                       int k)
{
     
    // Store the memorised values
    int [,,]dp = new int[n + 1, 2, k + 1];
 
    // Initialise
    for(int i = 0; i <= n; i++)
        for(int j = 0; j < 2; j++)
            for(int x = 0; x <= k; x++)
                dp[i, j, x] = 0;
 
    // Base
    dp[0, 0, 0] = 1;
 
    // Calculate all states
    // For every state, from numbers 1 to N,
    // the count of numbers which contain exactly j
    // non zero digits is being computed and updated
    // in the dp array.
    for(int i = 0; i < n; ++i)
    {
        int sm = 0;
        while (sm < 2)
        {
            for(int j = 0; j < k + 1; ++j)
            {
                int x = 0;
                while (x <= (sm !=
                       0 ? 9 : s[i]- '0'))
                {
                    if (j + (x > 0 ? 1 : 0) < k + 1)
                    {
                        dp[i + 1, ((sm != 0 || x <
                        (s[i] - '0')) ? 1 : 0),
                           j + (x > 0 ? 1 : 0)] +=
                         dp[i, sm, j];
                    }
                    ++x;
                }
            }
            ++sm;
        }
    }
 
    // Return the required answer
    return dp[n, 0, k] + dp[n, 1, k];
}
 
// Driver code
public static void Main(string[] args)
{
    string s = "25";
    int k = 2;
    int n = s.Length;
 
    // Function call
    Console.Write(k_nonzero_numbers(s, n, k));
}
}
 
// This code is contributed by rutvik_56

chevron_right


Output: 

14

 

Time Complexity: O(LK) where L is the number of digits in N. 
Note: The two for loops used to calculate the state which from [0, 1] and [0, 9] respectively are considered as a constant multiplication.
 

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

Recommended Posts:


pawanasipugmailcom

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.