给定一个正整数N ,任务是找到N位数字的数量,使得该数字中至少有一位数字出现了不止一次。
例子:
Input: N = 2
Output: 9
Explanation:
All the 2-digit number such that at least 1 digits occurs more than once are {11, 22, 33, 44, 55, 66, 77, 88, 99}. Therefore, the total count is 9.
Input: N = 5
Output: 62784
朴素方法:解决给定问题的最简单方法是生成所有可能的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)