📌  相关文章
📜  计数小于 N 的包含来自给定集合的数字的数字:Digit DP

📅  最后修改于: 2021-09-22 10:40:40             🧑  作者: Mango

给定一个整数N和一组数字D[] ,它由 [1, 9] 中的数字组成。任务是计算可能小于N的数字,其数字来自给定的数字集。
例子:

朴素的方法:检查范围[1,N]的所有数字的数字,如果一个数字的所有数字都属于给定的数字集,则将计数加1。
高效方法:思想是利用Digit DP的概念,遍历给定的一组数字,生成严格小于给定数字N的所有数字。递归地选择数字的所有可能位置的数字,并通过一个布尔变量,以检查通过包括数字,数量落入给定的范围或没有。
让我们想想DP可能的状态——

  1. pos :它告诉要选择的数字的位置,以便数字落在给定的范围内。
  2. :这将帮助我们了解当前数字是否受到限制。如果数字受到限制,则可以从给定的数字集中选择任何数字。否则,可以在 [1, N[pos]] 范围内选择数字。
  3. size :它会告诉要选择的位数。

下面是递归函数的说明:

  • 基本情况:这个问题的基本情况是当要选择的数字的位置等于要选择的数字长度时,只有一个可能的数字包含迄今为止选择的数字。
if (position == countDigits(N))
    return 1
  • 递归情况:为了生成给定范围内的数字,使用紧密变量选择范围内可能的数字,如下所示:
    • 如果tight 的值为0,则表示通过包含该数字将给出小于给定范围的数字。
    • 否则,如果tight 的值为1,表示通过包含该数字,它将给出大于给定范围的数字。所以我们可以在得到紧值 1 后删除所有排列,以避免更多的递归调用。
  • 在为每个位置选择每个数字后存储可能的数字计数。

下面是上述方法的实现:

C++
// C++ implementation to find the
// count of numbers possible less
// than N, such that every digit
// is from the given set of digits
#include 
 
using namespace std;
 
int dp[15][2];
 
// Function to convert integer
// into the string
string convertToString(int num)
{
    stringstream ss;
    ss << num;
    string s = ss.str();
    return s;
}
 
// Recursive function to find the
// count of numbers possible less
// than N, such that every digit
// is from the given set of digits
int calculate(int pos, int tight,
    int D[], int sz, string& num)
{
    // Base case
    if (pos == num.length())
        return 1;
     
    // Condition when the subproblem
    // is computed previously
    if (dp[pos][tight] != -1)
        return dp[pos][tight];
 
    int val = 0;
     
    // Condition when the number
    // chosen till now is definietly
    // smaller than the given number N
    if (tight == 0) {
         
        // Loop to traverse all the
        // digits of the given set
        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 {
        // Loop to traverse all the
        // digits from the given set
        for (int i = 0; i < sz; i++) {
            val += calculate(pos + 1,
                    tight, D, sz, num);
        }
    }
     
    // Store the solution for
    // current subproblem
    return dp[pos][tight] = val;
}
 
// Function to count the numbers
// less then N from given set of digits
int countNumbers(int D[], int N, int sz)
{
    // Converting the number to string
    string num = convertToString(N);
    int len = num.length();
     
    // Initially no subproblem
    // is solved till now
    memset(dp, -1, sizeof(dp));
     
    // Find the solution of all the
    // number equal to the length of
    // the given number N
    int ans = calculate(0, 0, D, sz, num);
     
    // Loop to find the number less in
    // in the length of the given number
    for (int i = 1; i < len; i++)
        ans += calculate(i, 1, D, sz, num);
 
    return ans;
}
 
// Driver Code
int main()
{
    int sz = 3;
 
    int D[sz] = { 1, 4, 9 };
    int N = 10;
     
    // Function Call
    cout << countNumbers(D, N, sz);
    return 0;
}


Java
// Java implementation to find the
// count of numbers possible less
// than N, such that every digit
// is from the given set of digits
import java.util.*;
 
class GFG{
  
static int [][]dp = new int[15][2];
  
// Function to convert integer
// into the String
static String convertToString(int num)
{
    return String.valueOf(num);
}
  
// Recursive function to find the
// count of numbers possible less
// than N, such that every digit
// is from the given set of digits
static int calculate(int pos, int tight,
    int D[], int sz, String num)
{
    // Base case
    if (pos == num.length())
        return 1;
      
    // Condition when the subproblem
    // is computed previously
    if (dp[pos][tight] != -1)
        return dp[pos][tight];
  
    int val = 0;
      
    // Condition when the number
    // chosen till now is definietly
    // smaller than the given number N
    if (tight == 0) {
          
        // Loop to traverse all the
        // digits of the given set
        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 {
        // Loop to traverse all the
        // digits from the given set
        for (int i = 0; i < sz; i++) {
            val += calculate(pos + 1,
                    tight, D, sz, num);
        }
    }
      
    // Store the solution for
    // current subproblem
    return dp[pos][tight] = val;
}
  
// Function to count the numbers
// less then N from given set of digits
static int countNumbers(int D[], int N, int sz)
{
    // Converting the number to String
    String num = convertToString(N);
    int len = num.length();
      
    // Initially no subproblem
    // is solved till now
    for (int i = 0; i < 15; i++)
        for (int j = 0; j < 2; j++)
            dp[i][j] = -1;
      
    // Find the solution of all the
    // number equal to the length of
    // the given number N
    int ans = calculate(0, 0, D, sz, num);
      
    // Loop to find the number less in
    // in the length of the given number
    for (int i = 1; i < len; i++)
        ans += calculate(i, 1, D, sz, num);
  
    return ans;
}
  
// Driver Code
public static void main(String[] args)
{
    int sz = 3;
  
    int D[] = { 1, 4, 9 };
    int N = 10;
      
    // Function Call
    System.out.print(countNumbers(D, N, sz));
}
}
 
// This code is contributed by Rajput-Ji


Python3
# Python3 implementation to find the
# count of numbers possible less
# than N, such that every digit
# is from the given set of digits
import numpy as np;
dp = np.ones((15,2))*-1;
 
# Function to convert integer
# into the string
def convertToString(num) :
    return str(num);
 
# Recursive function to find the
# count of numbers possible less
# than N, such that every digit
# is from the given set of digits
def calculate(pos,tight,  D, sz, num) :
 
    # Base case
    if (pos == len(num)):
        return 1;
     
    # Condition when the subproblem
    # is computed previously
    if (dp[pos][tight] != -1) :
        return dp[pos][tight];
 
    val = 0;
     
    # Condition when the number
    # chosen till now is definietly
    # smaller than the given number N
    if (tight == 0) :
         
        # Loop to traverse all the
        # digits of the given set
        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 :
        # Loop to traverse all the
        # digits from the given set
        for i in range(sz) :
            val += calculate(pos + 1, tight, D, sz, num);
             
    # Store the solution for
    # current subproblem
    dp[pos][tight] = val;
     
    return dp[pos][tight];
 
# Function to count the numbers
# less then N from given set of digits
def countNumbers(D, N, sz) :
 
    # Converting the number to string
    num = convertToString(N);
    length = len(num);
     
    # Initially no subproblem
    # is solved till now
    # dp = np.ones((15,2))*-1;
     
    # Find the solution of all the
    # number equal to the length of
    # the given number N
    ans = calculate(0, 0, D, sz, num);
     
    # Loop to find the number less in
    # in the length of the given number
    for i in range(1,length) :
        ans += calculate(i, 1, D, sz, num);
 
    return ans;
 
 
# Driver Code
if __name__ == "__main__" :
 
    sz = 3;
 
    D = [ 1, 4, 9 ];
    N = 10;
     
    # Function Call
    print(countNumbers(D, N, sz));
 
    # This code is contributed by AnkitRai01


C#
// C# implementation to find the
// count of numbers possible less
// than N, such that every digit
// is from the given set of digits
using System;
 
class GFG{
   
static int [,]dp = new int[15, 2];
   
// Function to convert integer
// into the String
static String convertToString(int num)
{
    return String.Join("",num);
}
   
// Recursive function to find the
// count of numbers possible less
// than N, such that every digit
// is from the given set of digits
static int calculate(int pos, int tight,
    int []D, int sz, String num)
{
    // Base case
    if (pos == num.Length)
        return 1;
       
    // Condition when the subproblem
    // is computed previously
    if (dp[pos,tight] != -1)
        return dp[pos,tight];
   
    int val = 0;
       
    // Condition when the number
    // chosen till now is definietly
    // smaller than the given number N
    if (tight == 0) {
           
        // Loop to traverse all the
        // digits of the given set
        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 {
        // Loop to traverse all the
        // digits from the given set
        for (int i = 0; i < sz; i++) {
            val += calculate(pos + 1,
                    tight, D, sz, num);
        }
    }
       
    // Store the solution for
    // current subproblem
    return dp[pos,tight] = val;
}
   
// Function to count the numbers
// less then N from given set of digits
static int countNumbers(int []D, int N, int sz)
{
    // Converting the number to String
    String num = convertToString(N);
    int len = num.Length;
       
    // Initially no subproblem
    // is solved till now
    for (int i = 0; i < 15; i++)
        for (int j = 0; j < 2; j++)
            dp[i,j] = -1;
       
    // Find the solution of all the
    // number equal to the length of
    // the given number N
    int ans = calculate(0, 0, D, sz, num);
       
    // Loop to find the number less in
    // in the length of the given number
    for (int i = 1; i < len; i++)
        ans += calculate(i, 1, D, sz, num);
   
    return ans;
}
   
// Driver Code
public static void Main(String[] args)
{
    int sz = 3;
   
    int []D = { 1, 4, 9 };
    int N = 10;
       
    // Function Call
    Console.Write(countNumbers(D, N, sz));
}
}
 
// This code is contributed by Princi Singh


Javascript


输出:
3

时间复杂度:O(Len(D))
空间复杂度:O(12*2)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程