📌  相关文章
📜  计算少于N的数字,其中包含给定集合中的数字:Digit DP

📅  最后修改于: 2021-05-04 12:57:19             🧑  作者: 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();
      
    // Intially 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();
       
    // Intially 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); 
      
    # Intially 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;
        
    // Intially 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


输出:
3

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