Sunday, September 22, 2024
Google search engine
HomeLanguagesDynamic ProgrammingCount of integers of length N and value less than K such...

Count of integers of length N and value less than K such that they contain digits only from the given set

Given a set of digits A[] in sorted order and two integers N and K, the task is to find how many numbers of length N are possible whose value is less than K and the digits are from the given set only. Note that you can use the same digit multiple times.

Examples: 

Input: A[] = {0, 1, 5}, N = 1, K = 2 
Output:
Only valid numbers are 0 and 1.

Input: A[] = {0, 1, 2, 5}, N = 2, K = 21 
Output:
10, 11, 12, 15 and 20 are the valid numbers. 
 

Approach: Let d be the size of A[]. We can break this problem into three simpler cases.  

  1. When N is greater than the length of K, It is obvious that if the length of N is greater than the length of k or if d is equal to 0, no such number is possible.
  2. When N is smaller than the length of K, then all possible combinations of digit of length N are valid. Also, we have to keep in mind that 0 can’t be in the first place. So, if A[] contains 0, the first place can be filled in (d – 1) ways. Since repetition is allowed and 0 can occupy the other places, rest N – 1 places can be filled in d * d * … * d(N – 1) times i.e. in dN – 1 ways. Therefore the answer is (d – 1) * (dN – 1) if A[] contains 0 else dN.
  3. When N is equal to the length of K, this is the trickiest part. We need to use Dynamic Programming for this part. Construct a digit array of K. Let’s call it digit[]. Let First(i) be the number formed by taking the first i digits of it. Let lower[i] denote the number of elements in A[] which are smaller than i
    For example, First(2) of 423 is 42. If A[] = {0, 2} then lower[0] = 0, lower[1] = 1, lower[2] = 1, lower[3] = 2. 
    Generate N digit numbers by dynamic programming. Let dp[i] denote total numbers of length i which are less than first i digits of K
    Elements in dp[i] can be generated by two cases: 
    • For all the numbers whose First(i – 1) is less than First(i – 1) of K, we can put any digit at ith index. Hence, dp[i] = dp[i] + (dp[i – 1] * d)
    • For all the numbers whose First(i – 1) is the same as First(i – 1) of K, we can only put those digits which are smaller than digit[i]. Hence, dp[i] = dp[i] + lower[digit[i]].

Below is the implementation of the above approach:  

C++14




// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
 
#define MAX 10
 
// Function to convert a number into vector
vector<int> numToVec(int N)
{
    vector<int> digit;
 
    // Push all the digits of N from the end
    // one by one to the vector
    while (N != 0) {
        digit.push_back(N % 10);
        N = N / 10;
    }
 
    // If the original number was 0
    if (digit.size() == 0)
        digit.push_back(0);
 
    // Reverse the vector elements
    reverse(digit.begin(), digit.end());
 
    // Return the required vector
    return digit;
}
 
// Function to return the count of B length integers
// which are less than C and they
// contain digits from set A[] only
int solve(vector<int>& A, int B, int C)
{
    vector<int> digit;
    int d, d2;
 
    // Convert number to digit array
    digit = numToVec(C);
    d = A.size();
 
    // Case 1: No such number possible as the
    // generated numbers will always
    // be greater than C
    if (B > digit.size() || d == 0)
        return 0;
 
    // Case 2: All integers of length B are valid
    // as they all are less than C
    else if (B < digit.size()) {
        // contain 0
        if (A[0] == 0 && B != 1)
            return (d - 1) * pow(d, B - 1);
        else
            return pow(d, B);
    }
 
    // Case 3
    else {
        int dp[B + 1] = { 0 };
        int lower[MAX + 1] = { 0 };
 
        // Update the lower[] array such that
        // lower[i] stores the count of elements
        // in A[] which are less than i
        for (int i = 0; i < d; i++)
            lower[A[i] + 1] = 1;
        for (int i = 1; i <= MAX; i++)
            lower[i] = lower[i - 1] + lower[i];
 
        bool flag = true;
        dp[0] = 0;
        for (int i = 1; i <= B; i++) {
            d2 = lower[digit[i - 1]];
            dp[i] = dp[i - 1] * d;
 
            // For first index we can't use 0
            if (i == 1 && A[0] == 0 && B != 1)
                d2 = d2 - 1;
 
            // Whether (i-1) digit of generated number
            // can be equal to (i - 1) digit of C
            if (flag)
                dp[i] += d2;
 
            // Is digit[i - 1] present in A ?
            flag = (flag & (lower[digit[i - 1] + 1]
                            == lower[digit[i - 1]] + 1));
        }
        return dp[B];
    }
}
 
// Driver code
int main()
{
 
    // Digits array
    vector<int> A = { 0, 1, 2, 5 };
    int N = 2;
    int k = 21;
 
    cout << solve(A, N, k);
 
    return 0;
}


Java




// Java implementation of the approach
import java.util.*;
 
class GFG
{
static int MAX = 10;
 
// Function to convert a number into vector
static Vector<Integer> numToVec(int N)
{
    Vector<Integer> digit = new Vector<Integer>();
 
    // Push all the digits of N from the end
    // one by one to the vector
    while (N != 0)
    {
        digit.add(N % 10);
        N = N / 10;
    }
 
    // If the original number was 0
    if (digit.size() == 0)
        digit.add(0);
 
    // Reverse the vector elements
    Collections.reverse(digit);
 
    // Return the required vector
    return digit;
}
 
// Function to return the count
// of B length integers which are
// less than C and they contain
// digits from set A[] only
static int solve(Vector<Integer> A, int B, int C)
{
    Vector<Integer> digit = new Vector<Integer>();
    int d, d2;
 
    // Convert number to digit array
    digit = numToVec(C);
    d = A.size();
 
    // Case 1: No such number possible as the
    // generated numbers will always
    // be greater than C
    if (B > digit.size() || d == 0)
        return 0;
 
    // Case 2: All integers of length B are valid
    // as they all are less than C
    else if (B < digit.size())
    {
        // contain 0
        if (A.get(0) == 0 && B != 1)
            return (int) ((d - 1) * Math.pow(d, B - 1));
        else
            return (int) Math.pow(d, B);
    }
 
    // Case 3
    else
    {
        int []dp = new int[B + 1];
        int []lower = new int[MAX + 1];
 
        // Update the lower[] array such that
        // lower[i] stores the count of elements
        // in A[] which are less than i
        for (int i = 0; i < d; i++)
            lower[A.get(i) + 1] = 1;
        for (int i = 1; i <= MAX; i++)
            lower[i] = lower[i - 1] + lower[i];
 
        boolean flag = true;
        dp[0] = 0;
        for (int i = 1; i <= B; i++)
        {
            d2 = lower[digit.get(i - 1)];
            dp[i] = dp[i - 1] * d;
 
            // For first index we can't use 0
            if (i == 1 && A.get(0) == 0 && B != 1)
                d2 = d2 - 1;
 
            // Whether (i-1) digit of generated number
            // can be equal to (i - 1) digit of C
            if (flag)
                dp[i] += d2;
 
            // Is digit[i - 1] present in A ?
            flag = (flag & (lower[digit.get(i - 1) + 1] ==
                            lower[digit.get(i - 1)] + 1));
        }
        return dp[B];
    }
}
 
// Driver code
public static void main(String[] args)
{
    Integer arr[] = { 0, 1, 2, 5 };
    // Digits array
    Vector<Integer> A = new Vector<>(Arrays.asList(arr));
    int N = 2;
    int k = 21;
 
    System.out.println(solve(A, N, k));
}
}
 
// This code is contributed
// by PrinciRaj1992


Python3




# Python3 implementation of the approach
MAX=10
 
# Function to convert a number into vector
def numToVec(N):
     
    digit = []
 
    # Push all the digits of N from the end
    # one by one to the vector
    while (N != 0):
        digit.append(N % 10)
        N = N // 10
 
    # If the original number was 0
    if (len(digit) == 0):
        digit.append(0)
 
    # Reverse the vector elements
    digit = digit[::-1]
 
    # Return the required vector
    return digit
 
 
# Function to return the count of B length integers
# which are less than C and they
# contain digits from set A[] only
def solve(A, B, C):
    d, d2 = 0,0
 
    # Convert number to digit array
    digit = numToVec(C)
    d = len(A)
 
    # Case 1: No such number possible as the
    # generated numbers will always
    # be greater than C
    if (B > len(digit) or d == 0):
        return 0
 
    # Case 2: All integers of length B are valid
    # as they all are less than C
    elif (B < len(digit)):
        # contain 0
        if (A[0] == 0 and B != 1):
            return (d - 1) * pow(d, B - 1)
        else:
            return pow(d, B)
 
    # Case 3
    else :
        dp=[0 for i in range(B + 1)]
        lower=[0 for i in range(MAX + 1)]
 
        # Update the lower[] array such that
        # lower[i] stores the count of elements
        # in A[] which are less than i
        for i in range(d):
            lower[A[i] + 1] = 1
        for i in range(1, MAX+1):
            lower[i] = lower[i - 1] + lower[i]
 
        flag = True
        dp[0] = 0
        for i in range(1, B+1):
            d2 = lower[digit[i - 1]]
            dp[i] = dp[i - 1] * d
 
            # For first index we can't use 0
            if (i == 1 and A[0] == 0 and B != 1):
                d2 = d2 - 1
 
            # Whether (i-1) digit of generated number
            # can be equal to (i - 1) digit of C
            if (flag):
                dp[i] += d2
 
            # Is digit[i - 1] present in A ?
            flag = (flag & (lower[digit[i - 1] + 1] == lower[digit[i - 1]] + 1))
         
        return dp[B]
 
# Driver code
 
# Digits array
A =[0, 1, 2, 5]
N = 2
k = 21
 
print(solve(A, N, k))
 
# This code is contributed by mohit kumar 29


C#




// C# implementation of the approach
using System;
using System.Collections.Generic;
 
class GFG
{
static int MAX = 10;
 
// Function to convert a number into vector
static List<int> numToVec(int N)
{
    List<int> digit = new List<int>();
 
    // Push all the digits of N from the end
    // one by one to the vector
    while (N != 0)
    {
        digit.Add(N % 10);
        N = N / 10;
    }
 
    // If the original number was 0
    if (digit.Count == 0)
        digit.Add(0);
 
    // Reverse the vector elements
    digit.Reverse();
 
    // Return the required vector
    return digit;
}
 
// Function to return the count
// of B length integers which are
// less than C and they contain
// digits from set A[] only
static int solve(List<int> A, int B, int C)
{
    List<int> digit = new List<int>();
    int d, d2;
 
    // Convert number to digit array
    digit = numToVec(C);
    d = A.Count;
 
    // Case 1: No such number possible as the
    // generated numbers will always
    // be greater than C
    if (B > digit.Count || d == 0)
        return 0;
 
    // Case 2: All integers of length B are valid
    // as they all are less than C
    else if (B < digit.Count)
    {
        // contain 0
        if (A[0] == 0 && B != 1)
            return (int) ((d - 1) * Math.Pow(d, B - 1));
        else
            return (int) Math.Pow(d, B);
    }
 
    // Case 3
    else
    {
        int []dp = new int[B + 1];
        int []lower = new int[MAX + 1];
 
        // Update the lower[] array such that
        // lower[i] stores the count of elements
        // in A[] which are less than i
        for (int i = 0; i < d; i++)
            lower[A[i] + 1] = 1;
        for (int i = 1; i <= MAX; i++)
            lower[i] = lower[i - 1] + lower[i];
 
        Boolean flag = true;
        dp[0] = 0;
        for (int i = 1; i <= B; i++)
        {
            d2 = lower[digit[i-1]];
            dp[i] = dp[i - 1] * d;
 
            // For first index we can't use 0
            if (i == 1 && A[0] == 0 && B != 1)
                d2 = d2 - 1;
 
            // Whether (i-1) digit of generated number
            // can be equal to (i - 1) digit of C
            if (flag)
                dp[i] += d2;
 
            // Is digit[i - 1] present in A ?
            flag = (flag & (lower[digit[i-1] + 1] ==
                            lower[digit[i-1]] + 1));
        }
        return dp[B];
    }
}
 
// Driver code
public static void Main(String[] args)
{
    int []arr = { 0, 1, 2, 5 };
     
    // Digits array
    List<int> A = new List<int>(arr);
    int N = 2;
    int k = 21;
 
    Console.WriteLine(solve(A, N, k));
}
}
 
// This code is contributed by Rajput-Ji


Javascript




<script>
 
// Javascript implementation of the approach
let MAX = 10;
 
// Function to convert a number into vector
function numToVec(N)
{
    let digit = [];
         
    // Push all the digits of N from the end
    // one by one to the vector
    while (N != 0)
    {
        digit.push(N % 10);
        N = Math.floor(N / 10);
    }
   
    // If the original number was 0
    if (digit.length == 0)
        digit.push(0);
   
    // Reverse the vector elements
    digit.reverse();
   
    // Return the required vector
    return digit;
}
 
// Function to return the count
// of B length integers which are
// less than C and they contain
// digits from set A[] only
function solve(A, B, C)
{
    let digit = [];
    let d, d2;
   
    // Convert number to digit array
    digit = numToVec(C);
    d = A.length;
   
    // Case 1: No such number possible as the
    // generated numbers will always
    // be greater than C
    if (B > digit.length || d == 0)
        return 0;
   
    // Case 2: All integers of length B are valid
    // as they all are less than C
    else if (B < digit.length)
    {
         
        // contain 0
        if (A[0] == 0 && B != 1)
            return  Math.floor((d - 1) *
                    Math.pow(d, B - 1));
        else
            return Math.floor(Math.pow(d, B));
    }
   
    // Case 3
    else
    {
        let dp = new Array(B + 1);
        let lower = new Array(MAX + 1);
         
          for(let i = 0; i < dp.length; i++)
        {
            dp[i] = 0;
        }
        for(let i = 0; i < lower.length; i++)
        {
            lower[i] = 0;
        }
         
        // Update the lower[] array such that
        // lower[i] stores the count of elements
        // in A[] which are less than i
        for(let i = 0; i < d; i++)
            lower[A[i] + 1] = 1;
        for(let i = 1; i <= MAX; i++)
            lower[i] = lower[i - 1] + lower[i];
   
        let flag = true;
        dp[0] = 0;
        for(let i = 1; i <= B; i++)
        {
            d2 = lower[digit[i - 1]];
            dp[i] = dp[i - 1] * d;
   
            // For first index we can't use 0
            if (i == 1 && A[0] == 0 && B != 1)
                d2 = d2 - 1;
   
            // Whether (i-1) digit of generated number
            // can be equal to (i - 1) digit of C
            if (flag)
                dp[i] += d2;
   
            // Is digit[i - 1] present in A ?
            flag = (flag & (lower[digit[i - 1] + 1] ==
                            lower[digit[i - 1]] + 1));
        }
        return dp[B];
    }
}
 
// Driver code
let arr = [ 0, 1, 2, 5 ];
let N = 2;
let k = 21;
 
document.write(solve(arr, N, k));
     
// This code is contributed by patel2127
 
</script>


Output: 

5

 

Time complexity: O(N)
Auxiliary Space: O(N), since N extra space has been taken.

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 neveropen!

Dominic Rubhabha-Wardslaus
Dominic Rubhabha-Wardslaushttp://wardslaus.com
infosec,malicious & dos attacks generator, boot rom exploit philanthropist , wild hacker , game developer,
RELATED ARTICLES

Most Popular

Recent Comments