📌  相关文章
📜  至少有一位重复的 N 位数字的计数

📅  最后修改于: 2021-09-17 07:25:49             🧑  作者: Mango

给定一个正整数N ,任务是找到N位数字的数量,使得该数字中至少有一位数字出现了不止一次。

例子:

朴素方法:解决给定问题的最简单方法是生成所有可能的N位数字,并计算那些至少有一位数字出现多次的数字。检查所有数字后,打印计数值作为结果的总数字计数。

时间复杂度: O(N *10 N )
辅助空间: O(1)

高效方法:上述方法也可以使用动态规划进行优化,因为上述问题具有重叠子问题和最优子结构。子问题可以存储在dp[][][]表记忆中,其中dp[digit][mask][repeated]存储从第 th位到末尾的答案,其中掩码存储数字中包含的所有数字,直到现在和重复表示是否有任何数字出现了多次。请按照以下步骤解决问题:

  • 初始化一个全局多维数组dp[50][1024][2] ,所有值都为-1 ,用于存储每个递归调用的结果。
  • 通过执行以下步骤定义一个递归函数,比如countOfNumbers(digit, mask, repeat, N)
    • 如果数字的值等于(N + 1)则返回1作为有效的N位数字,如果重复等于true 。否则,返回0
    • 如果重复等于true ,则返回pow(10, N – digit + 1)
    • 如果已经计算了状态dp[digit][mask][repeated] 的结果,则返回此值dp[digit][mask][repeated]
    • 如果当前数字1 ,则可以放置[1, 9] 中的任何数字,如果N = 1 ,则也可以放置0
    • 迭代范围[N == 1 ? 0 : 1, 9]使用变量i并执行以下步骤:
      • 如果设置了掩码的i 位,则将countOfNumbers(digit + 1, mask|(1<的值相加
      • 否则,添加countOfNumbers(digit + 1, mask|(1<
    • 否则,使用变量i迭代范围[0, 9]并执行以下步骤:
      • 如果设置了掩码的i 位,则将countOfNumbers(digit + 1, mask|(1<的值相加
      • 否则,添加countOfNumbers(digit + 1, mask|(1<
    • 作为当前递归调用的结果,返回所有可能的有效数字val位置的总和。
  • 打印函数countOfNumbers(1, 0, 0, N)返回的值作为满足给定条件的 N 位数字的结果计数。

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
 
int dp[50][1 << 10][2];
 
// Function to find the number of N
// digit numbers such that at least
// one digit occurs more than once
int countOfNumbers(int digit, int mask,
                   bool repeated, int n)
{
    // Base Case
    if (digit == n + 1) {
        if (repeated == true) {
            return 1;
        }
        return 0;
    }
 
    // If repeated is true, then for
    // remaining positions any digit
    // can be placed
    if (repeated == true) {
        return pow(10, n - digit + 1);
    }
 
    // If the current state has already
    // been computed, then return it
    int& val = dp[digit][mask][repeated];
    if (val != -1) {
        return val;
    }
 
    // Stores the count of number for
    // the current recursive calls
    val = 0;
 
    // If current position is 1, then
    // any digit can be placed.
 
    // If n = 1, 0 can be also placed
    if (digit == 1) {
 
        for (int i = (n == 1 ? 0 : 1);
             i <= 9; ++i) {
 
            // If a digit has occurred
            // for the second time, then
            // set repeated to 1
            if (mask & (1 << i)) {
                val += countOfNumbers(
                    digit + 1, mask | (1 << i), 1, n);
            }
 
            // Otherwise
            else {
                val += countOfNumbers(
                    digit + 1, mask | (1 << i), 0, n);
            }
        }
    }
 
    // For remaining positions any
    // digit can be placed
    else {
        for (int i = 0; i <= 9; ++i) {
 
            // If a digit has occurred
            // for the second time, then
            // set repeated to 1
            if (mask & (1 << i)) {
                val += countOfNumbers(
                    digit + 1, mask | (1 << i), 1, n);
            }
            else {
                val += countOfNumbers(
                    digit + 1, mask | (1 << i), 0, n);
            }
        }
    }
 
    // Return the resultant count for
    // the current recursive call
    return val;
}
 
// Function to count all the N-digit
// numbers having at least one digit's
// occurrence more than once
void countNDigitNumber(int N)
{
    // Initialize dp array with -1
    memset(dp, -1, sizeof dp);
 
    // Function to count all possible
    // number satisfying the given
    // criteria
    cout << countOfNumbers(1, 0, 0, N);
}
 
// Driver Code
int main()
{
    int N = 2;
    countNDigitNumber(N);
 
    return 0;
}


Java
import java.util.Arrays;
 
// Java program for the above approach
 
class GFG {
 
    public static int[][][] dp = new int[50][1 << 10][2];
 
    // Function to find the number of N
    // digit numbers such that at least
    // one digit occurs more than once
    public static int countOfNumbers(int digit, int mask,
                                     int repeated, int n)
    {
       
        // Base Case
        if (digit == n + 1) {
            if (repeated == 1) {
                return 1;
            }
            return 0;
        }
 
        // If repeated is true, then for
        // remaining positions any digit
        // can be placed
        if (repeated == 1) {
            return (int) Math.pow(10, n - digit + 1);
        }
 
        // If the current state has already
        // been computed, then return it
        int val = dp[digit][mask][repeated];
        if (val != -1) {
            return val;
        }
 
        // Stores the count of number for
        // the current recursive calls
        val = 0;
 
        // If current position is 1, then
        // any digit can be placed.
 
        // If n = 1, 0 can be also placed
        if (digit == 1) {
 
            for (int i = (n == 1 ? 0 : 1); i <= 9; ++i) {
 
                // If a digit has occurred
                // for the second time, then
                // set repeated to 1
                if ((mask & (1 << i)) > 0) {
                    val += countOfNumbers(digit + 1, mask | (1 << i), 1, n);
                }
 
                // Otherwise
                else {
                    val += countOfNumbers(digit + 1, mask | (1 << i), 0, n);
                }
            }
        }
 
        // For remaining positions any
        // digit can be placed
        else {
            for (int i = 0; i <= 9; ++i) {
 
                // If a digit has occurred
                // for the second time, then
                // set repeated to 1
                if ((mask & (1 << i)) > 0) {
                    val += countOfNumbers(digit + 1, mask | (1 << i), 1, n);
                } else {
                    val += countOfNumbers(digit + 1, mask | (1 << i), 0, n);
                }
            }
        }
 
        // Return the resultant count for
        // the current recursive call
        return val;
    }
 
    // Function to count all the N-digit
    // numbers having at least one digit's
    // occurrence more than once
    public static void countNDigitNumber(int N)
    {
       
        // Initialize dp array with -1
        for (int i = 0; i < 50; i++) {
            for (int j = 0; j < 1 << 10; j++) {
                for (int k = 0; k < 2; k++) {
                    dp[i][j][k] = -1;
                }
            }
        }
       
        // Function to count all possible
        // number satisfying the given
        // criteria
        System.out.println(countOfNumbers(1, 0, 0, N));
    }
 
    // Driver Code
    public static void main(String args[])
    {
        int N = 2;
        countNDigitNumber(N);
 
    }
}
 
// This code is contributed by gfgking.


Python3
# Python program for the above approach
 
dp = [[[-1 for i in range(2)] for i in range(1 << 10)] for i in range(50)]
 
# Function to find the number of N
# digit numbers such that at least
# one digit occurs more than once
def countOfNumbers(digit, mask, repeated, n):
    global dp
    # Base Case
    if (digit == n + 1):
        if (repeated == True):
            return 1
        return 0
 
    # If repeated is true, then for
    # remaining positions any digit
    # can be placed
    if (repeated == True):
        return pow(10, n - digit + 1)
 
    # If the current state has already
    # been computed, then return it
    val = dp[digit][mask][repeated]
    if (val != -1):
        return val
 
    # Stores the count of number for
    # the current recursive calls
    val = 4
 
    # If current position is 1, then
    # any digit can be placed.
 
    # If n = 1, 0 can be also placed
    if (digit == 1):
 
        for i in range((0 if (n==1) else 1),10):
            # If a digit has occurred
            # for the second time, then
            # set repeated to 1
            if (mask & (1 << i)):
                val += countOfNumbers(digit + 1, mask | (1 << i), 1, n)
            # Otherwise
        else:
                val += countOfNumbers(digit + 1, mask | (1 << i), 0, n)
 
    # For remaining positions any
    # digit can be placed
    else:
        for i in range(10):
            # If a digit has occurred
            # for the second time, then
            # set repeated to 1
            if (mask & (1 << i)):
                val += countOfNumbers(digit + 1, mask | (1 << i), 1, n)
        else:
                val += countOfNumbers(digit + 1, mask | (1 << i), 0, n)
 
    # Return the resultant count for
    # the current recursive call
    dp[digit][mask][repeated] = val
    return dp[digit][mask][repeated]
 
# Function to count all the N-digit
# numbers having at least one digit's
# occurrence more than once
def countNDigitNumber(N):
 
    # Function to count all possible
    # number satisfying the given
    # criteria
    print  (countOfNumbers(1, 0, 0, N))
 
# Driver Code
if __name__ == '__main__':
    N = 2
    countNDigitNumber(N)
 
# This code is contributed by mohit kumar 29.


C#
// C# program for the above approach
using System;
 
class GFG{
 
public static int[,,] dp = new int[50, 1 << 10, 2];
 
// Function to find the number of N
// digit numbers such that at least
// one digit occurs more than once
public static int countOfNumbers(int digit, int mask,
                                 int repeated, int n)
{
     
    // Base Case
    if (digit == n + 1)
    {
        if (repeated == 1)
        {
            return 1;
        }
        return 0;
    }
 
    // If repeated is true, then for
    // remaining positions any digit
    // can be placed
    if (repeated == 1)
    {
        return(int)Math.Pow(10, n - digit + 1);
    }
 
    // If the current state has already
    // been computed, then return it
    int val = dp[digit, mask, repeated];
    if (val != -1)
    {
        return val;
    }
 
    // Stores the count of number for
    // the current recursive calls
    val = 0;
 
    // If current position is 1, then
    // any digit can be placed.
 
    // If n = 1, 0 can be also placed
    if (digit == 1)
    {
        for(int i = (n == 1 ? 0 : 1); i <= 9; ++i)
        {
             
            // If a digit has occurred
            // for the second time, then
            // set repeated to 1
            if ((mask & (1 << i)) > 0)
            {
                val += countOfNumbers(
                    digit + 1, mask | (1 << i), 1, n);
            }
 
            // Otherwise
            else
            {
                val += countOfNumbers(
                    digit + 1, mask | (1 << i), 0, n);
            }
        }
    }
 
    // For remaining positions any
    // digit can be placed
    else
    {
        for(int i = 0; i <= 9; ++i)
        {
             
            // If a digit has occurred
            // for the second time, then
            // set repeated to 1
            if ((mask & (1 << i)) > 0)
            {
                val += countOfNumbers(
                    digit + 1, mask | (1 << i), 1, n);
            }
            else
            {
                val += countOfNumbers(
                    digit + 1, mask | (1 << i), 0, n);
            }
        }
    }
 
    // Return the resultant count for
    // the current recursive call
    return val;
}
 
// Function to count all the N-digit
// numbers having at least one digit's
// occurrence more than once
public static void countNDigitNumber(int N)
{
     
    // Initialize dp array with -1
    for(int i = 0; i < 50; i++)
    {
        for(int j = 0; j < 1 << 10; j++)
        {
            for(int k = 0; k < 2; k++)
            {
                dp[i, j, k] = -1;
            }
        }
    }
 
    // Function to count all possible
    // number satisfying the given
    // criteria
    Console.Write(countOfNumbers(1, 0, 0, N));
}
 
// Driver Code
public static void Main()
{
    int N = 2;
     
    countNDigitNumber(N);
}
}
 
// This code is contributed by ukasp


Javascript


输出:
9

时间复杂度: O(10 * N * 2 10 * 2 )
辅助空间: O(N*2 10 *2)