给定两个代表范围的正整数L和R以及另外两个正整数d和K。任务是找到数字d恰好出现K次的范围内的数字计数。
例子:
Input: L = 11, R = 100, d = 2, k = 1
Output: 17
Required numbers are 12, 20, 21, 23, 24, 25, 26, 27, 28, 29, 32, 42, 52, 62, 72, 82 and 92.
Input: L = 95, R = 1005, d = 0, k = 2
Output: 14
先决条件:Digit DP
方法:首先,如果我们能够计算所需的数字,直到R,即在[0,R]范围内,则可以通过求解从零到R的值,然后减去该值,就可以轻松地在[L,R]范围内得出答案。从零到L – 1求解后得到的答案。现在,我们需要定义DP状态。
DP州:
在最后的递归调用中,如果我们在最后一个位置,如果数字d的计数等于K,则返回1,否则返回0。
下面是上述方法的实现:
C++
// CPP Program to find the count of
// numbers in a range where digit d
// occurs exactly K times
#include
using namespace std;
const int M = 20;
// states - position, count, tight, nonz
int dp[M][M][2][2];
// d is required digit and K is occurrence
int d, K;
// This function returns the count of
// required numbers from 0 to num
int count(int pos, int cnt, int tight,
int nonz, vector num)
{
// Last position
if (pos == num.size()) {
if (cnt == K)
return 1;
return 0;
}
// If this result is already computed
// simply return it
if (dp[pos][cnt][tight][nonz] != -1)
return dp[pos][cnt][tight][nonz];
int ans = 0;
// Maximum limit upto which we can place
// digit. If tight is 1, means number has
// already become smaller so we can place
// any digit, otherwise num[pos]
int limit = (tight ? 9 : num[pos]);
for (int dig = 0; dig <= limit; dig++) {
int currCnt = cnt;
// Nonz is true if we placed a non
// zero digit at the starting of
// the number
if (dig == d) {
if (d != 0 || (!d && nonz))
currCnt++;
}
int currTight = tight;
// At this position, number becomes
// smaller
if (dig < num[pos])
currTight = 1;
// Next recursive call, also set nonz
// to 1 if current digit is non zero
ans += count(pos + 1, currCnt,
currTight, nonz || (dig != 0), num);
}
return dp[pos][cnt][tight][nonz] = ans;
}
// Function to convert x into its digit vector and uses
// count() function to return the required count
int solve(int x)
{
vector num;
while (x) {
num.push_back(x % 10);
x /= 10;
}
reverse(num.begin(), num.end());
// Initialize dp
memset(dp, -1, sizeof(dp));
return count(0, 0, 0, 0, num);
}
// Driver Code to test above functions
int main()
{
int L = 11, R = 100;
d = 2, K = 1;
cout << solve(R) - solve(L - 1) << endl;
return 0;
}
Java
// Java Program to find the count of
// numbers in a range where digit d
// occurs exactly K times
import java.util.*;
class Solution
{
static final int M = 20;
// states - position, count, tight, nonz
static int dp[][][][]= new int[M][M][2][2];
// d is required digit and K is occurrence
static int d, K;
// This function returns the count of
// required numbers from 0 to num
static int count(int pos, int cnt, int tight,
int nonz, Vector num)
{
// Last position
if (pos == num.size()) {
if (cnt == K)
return 1;
return 0;
}
// If this result is already computed
// simply return it
if (dp[pos][cnt][tight][nonz] != -1)
return dp[pos][cnt][tight][nonz];
int ans = 0;
// Maximum limit upto which we can place
// digit. If tight is 1, means number has
// already become smaller so we can place
// any digit, otherwise num[pos]
int limit = ((tight !=0)? 9 : num.get(pos));
for (int dig = 0; dig <= limit; dig++) {
int currCnt = cnt;
// Nonz is true if we placed a non
// zero digit at the starting of
// the number
if (dig == d) {
if (d != 0 || (d==0 && nonz!=0))
currCnt++;
}
int currTight = tight;
// At this position, number becomes
// smaller
if (dig < num.get(pos))
currTight = 1;
// Next recursive call, also set nonz
// to 1 if current digit is non zero
ans += count(pos + 1, currCnt,
currTight, (dig != 0?1:0), num);
}
return dp[pos][cnt][tight][nonz] = ans;
}
// Function to convert x into its digit vector and uses
// count() function to return the required count
static int solve(int x)
{
Vector num= new Vector();
while (x!=0) {
num.add(x % 10);
x /= 10;
}
Collections.reverse(num);
// Initialize dp
for(int i=0;i
Python3
# Python Program to find the count of
# numbers in a range where digit d
# occurs exactly K times
M = 20
# states - position, count, tight, nonz
dp = []
# d is required digit and K is occurrence
d, K = None, None
# This function returns the count of
# required numbers from 0 to num
def count(pos, cnt, tight, nonz, num: list):
# Last position
if pos == len(num):
if cnt == K:
return 1
return 0
# If this result is already computed
# simply return it
if dp[pos][cnt][tight][nonz] != -1:
return dp[pos][cnt][tight][nonz]
ans = 0
# Maximum limit upto which we can place
# digit. If tight is 1, means number has
# already become smaller so we can place
# any digit, otherwise num[pos]
limit = 9 if tight else num[pos]
for dig in range(limit + 1):
currCnt = cnt
# Nonz is true if we placed a non
# zero digit at the starting of
# the number
if dig == d:
if d != 0 or not d and nonz:
currCnt += 1
currTight = tight
# At this position, number becomes
# smaller
if dig < num[pos]:
currTight = 1
# Next recursive call, also set nonz
# to 1 if current digit is non zero
ans += count(pos + 1, currCnt,
currTight, (nonz or dig != 0), num)
dp[pos][cnt][tight][nonz] = ans
return dp[pos][cnt][tight][nonz]
# Function to convert x into its digit vector and uses
# count() function to return the required count
def solve(x):
global dp, K, d
num = []
while x:
num.append(x % 10)
x //= 10
num.reverse()
# Initialize dp
dp = [[[[-1, -1] for i in range(2)]
for j in range(M)] for k in range(M)]
return count(0, 0, 0, 0, num)
# Driver Code
if __name__ == "__main__":
L = 11
R = 100
d = 2
K = 1
print(solve(R) - solve(L - 1))
# This code is contributed by
# sanjeev2552
C#
// C# Program to find the count of
// numbers in a range where digit d
// occurs exactly K times
using System;
using System.Collections.Generic;
class GFG
{
static readonly int M = 20;
// states - position, count, tight, nonz
static int [,,,]dp= new int[M, M, 2, 2];
// d is required digit and K is occurrence
static int d, K;
// This function returns the count of
// required numbers from 0 to num
static int count(int pos, int cnt, int tight,
int nonz, List num)
{
// Last position
if (pos == num.Count)
{
if (cnt == K)
return 1;
return 0;
}
// If this result is already computed
// simply return it
if (dp[pos, cnt, tight, nonz] != -1)
return dp[pos, cnt, tight, nonz];
int ans = 0;
// Maximum limit upto which we can place
// digit. If tight is 1, means number has
// already become smaller so we can place
// any digit, otherwise num[pos]
int limit = ((tight != 0) ? 9 : num[pos]);
for (int dig = 0; dig <= limit; dig++)
{
int currCnt = cnt;
// Nonz is true if we placed a non
// zero digit at the starting of
// the number
if (dig == d)
{
if (d != 0 || (d == 0 && nonz != 0))
currCnt++;
}
int currTight = tight;
// At this position, number becomes
// smaller
if (dig < num[pos])
currTight = 1;
// Next recursive call, also set nonz
// to 1 if current digit is non zero
ans += count(pos + 1, currCnt,
currTight, (dig != 0 ? 1 : 0), num);
}
return dp[pos, cnt, tight, nonz] = ans;
}
// Function to convert x into its
// digit vector and uses count()
// function to return the required count
static int solve(int x)
{
List num = new List();
while (x != 0)
{
num.Add(x % 10);
x /= 10;
}
num.Reverse();
// Initialize dp
for(int i = 0; i < M; i++)
for(int j = 0; j < M; j++)
for(int k = 0; k < 2; k++)
for(int l = 0; l < 2; l++)
dp[i, j, k, l]=-1;
return count(0, 0, 0, 0, num);
}
// Driver Code
public static void Main()
{
int L = 11, R = 100;
d = 2; K = 1;
Console.Write( solve(R) - solve(L - 1) );
}
}
// This code is contributed by Rajput-JI
输出:
17