给定一组按排序顺序排列的数字A[]和两个整数N和K ,任务是找出可能有多少个长度为N且其值小于K且数字仅来自给定集合的数字。请注意,您可以多次使用同一个数字。
例子:
Input: A[] = {0, 1, 5}, N = 1, K = 2
Output: 2
Only valid numbers are 0 and 1.
Input: A[] = {0, 1, 2, 5}, N = 2, K = 21
Output: 5
10, 11, 12, 15 and 20 are the valid numbers.
方法:让d是A[]的大小。我们可以将这个问题分解为三个更简单的情况。
- 当N大于K的长度时,很明显,如果 N 的长度大于 k 的长度或如果 d 等于 0,则不可能有这样的数字。
- 当N小于K的长度时,则长度为N的数字的所有可能组合都是有效的。此外,我们必须记住, 0不能放在首位。因此,如果A[]包含0 ,则可以用(d – 1)种方式填充第一位。由于允许重复并且0可以占据其他位置,因此可以用d * d * … * d(N – 1)次即d N – 1种方式填充剩余的N – 1个位置。因此答案是(d – 1) * (d N – 1 )如果A[]包含0否则d N 。
- 当N等于K的长度时,这是最棘手的部分。这部分我们需要使用动态规划。构造K的数字数组。我们称之为digit[] 。让First(i)是取它的前i位数字形成的数字。让lower[i]表示A[]中小于i的元素数量。
例如,423 的 First(2) 是 42。如果 A[] = {0, 2} 则 lower[0] = 0,lower[1] = 1,lower[2] = 1,lower[3] = 2 .
通过动态规划生成N位数字。让dp[i]表示小于K 的前i 个数字的长度i 的总数。
dp[i] 中的元素可以通过两种情况生成:- 对于First(i – 1)小于K 的First(i – 1)的所有数字,我们可以将任何数字放在第i个索引处。因此, dp[i] = dp[i] + (dp[i – 1] * d)
- 对于First(i – 1)与K的First(i – 1)相同的所有数字,我们只能放置那些小于digit[i] 的数字。因此, dp[i] = dp[i] + lower[digit[i]] 。
下面是上述方法的实现:
C++14
// C++ implementation of the approach
#include
using namespace std;
#define MAX 10
// Function to convert a number into vector
vector numToVec(int N)
{
vector 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& A, int B, int C)
{
vector 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 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 numToVec(int N)
{
Vector digit = new Vector();
// 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 A, int B, int C)
{
Vector digit = new Vector();
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 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 numToVec(int N)
{
List digit = new List();
// 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 A, int B, int C)
{
List digit = new List();
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 A = new List(arr);
int N = 2;
int k = 21;
Console.WriteLine(solve(A, N, k));
}
}
// This code is contributed by Rajput-Ji
Javascript
输出:
5
时间复杂度: O(N)
辅助空间: O(N)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。