给定一个整数N ,任务是计算最多两个N ,且两个相邻数字之间的绝对差最大为K。
注意:对于任何数字,整数0的计数都是相当大的。
例子:
Input: N = 20, K = 2
Output: 15
Explanation:
The required numbers are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 and 20. Notice that 14, 15, 16, 17, 18 and 19 all have adjacent digit’s absolute difference greater than K = 2 and thus they are not counted.
Input: N = 30, K = 3
Output: 22
Explanation:
All numbers upto 30 except 15, 16, 17, 18, 19, 26, 27, 28, 29 are accepted.
天真的方法:想法是迭代到N并检查K是否存在差异的所有数字。如果是,则将其计数,否则跳过该数字并继续进行迭代。
时间复杂度: O(N)
辅助空间: O(1)
高效方法:可以使用数字动态编程来优化此问题。以下是给定问题的详细dp状态。
- 在Digit Dp中,我们将我们的数字视为数字序列,因此需要一个状态位置,因此标记我们当前处于哪个状态。在每个递归调用中,尝试通过从0到9放置一个数字并递增位置来从左到右构建序列。
- 前一位数字仅存储与前一位数字的绝对差最大为K的那些数字。因此,前一个数字需要另一个状态。
- Tight ,state告诉我们我们要构建的数字是否已经小于N,因此在接下来的递归调用中,我们可以将0到9之间的任何数字放置。否则,可以一直放置到N的数字直到当前位置。
- 初始化一个布尔变量Start ,它告诉数字是否已经开始。如果该数字尚未开始,则可以通过将数字(从1到相对于当前位置的紧密度)设置到上限来开始该数字。否则,请在不开始编号的情况下重复进行。
- 在每个递归调用中,相对于前一个数字设置当前数字,以使它们之间的绝对差不超过K。在基本情况下,如果到达最后一个位置,则返回1。
下面是上述方法的实现:
C++
// C++ program to get the count
// of numbers upto N having
// absolute difference at most K
// between any two adjacent digits
#include
using namespace std;
// Table to store solution
// of each subproblem
long long dp[1002][10][2][2];
// Function to calculate
// all possible numbers
long long possibleNumbers(
int pos, int previous, bool tight,
bool start, string N, int K)
{
// Check if position reaches end that is
// is equal to length of N
if (pos == N.length())
return 1;
// Check if the result is
// already computed
// simply return it
if (dp[pos][previous][tight][start] != -1)
return dp[pos][previous][tight][start];
int res = 0;
// Maximum limit upto which we can place
// digit. If tight is false, means number has
// already become smaller so we can place
// any digit, otherwise N[pos]
int upper_limit
= (tight)
? (N[pos] - '0')
: 9;
int new_tight;
// Chekc if start is false the number
// has not started yet
if (!start) {
// Check if we do not start
// the number at pos
// then recur forward
res = possibleNumbers(
pos + 1, previous,
false, false, N, K);
// If we start the number
// we can place any digit
// from 1 to upper_limit
for (int i = 1; i <= upper_limit; i++) {
// Finding the new tight
new_tight
= (tight
&& i == upper_limit)
? 1
: 0;
res += possibleNumbers(
pos + 1, i, new_tight,
true, N, K);
}
}
// Condition if the number
// has already started
else {
// We can place digit upto
// upperbound & absolute difference
// with previous digit much
// be atmost K
for (int i = 0; i <= upper_limit; i++) {
new_tight = (tight
&& i == upper_limit)
? 1
: 0;
// Absolute difference atmost K
if (abs(i - previous) <= K)
res += possibleNumbers(
pos + 1, i,
new_tight, true, N, K);
}
}
// Store the solution
// to this subproblem
dp[pos][previous][tight][start] = res;
return dp[pos][previous][tight][start];
}
// Driver code
int main(void)
{
string N = "20";
int K = 2;
// Initialising the
// table with -1
memset(dp, -1, sizeof dp);
// Function call
cout << possibleNumbers(
0, 0, true,
false, N, K)
<< endl;
}
Java
// Java program to get the count
// of numbers upto N having
// absolute difference at most K
// between any two adjacent digits
import java.util.*;
class GFG{
// Table to store solution
// of each subproblem
static int [][][][]dp = new int[1002][10][2][2];
// Function to calculate
// all possible numbers
static int possibleNumbers(int pos, int previous,
int tight, int start,
String N, int K)
{
// Check if position reaches end
// that is equal to length of N
if (pos == N.length())
return 1;
// Check if the result is already
// computed simply return it
if (dp[pos][previous][tight][start] != -1)
return dp[pos][previous][tight][start];
int res = 0;
// Maximum limit upto which we can
// place digit. If tight is false,
// means number has already become
// smaller so we can place
// any digit, otherwise N[pos]
int upper_limit = (tight == 1) ?
(N.charAt(pos) - '0') : 9;
int new_tight;
// Check if start is false the number
// has not started yet
if (start == 0)
{
// Check if we do not start
// the number at pos
// then recur forward
res = possibleNumbers(pos + 1, previous,
0, 0, N, K);
// If we start the number
// we can place any digit
// from 1 to upper_limit
for(int i = 1; i <= upper_limit; i++)
{
// Finding the new tight
new_tight = (tight > 0 &&
i == upper_limit) ? 1 : 0;
res += possibleNumbers(pos + 1, i,
new_tight,
1, N, K);
}
}
// Condition if the number
// has already started
else
{
// We can place digit upto
// upperbound & absolute difference
// with previous digit much
// be atmost K
for(int i = 0; i <= upper_limit; i++)
{
new_tight = (tight > 0 &&
i == upper_limit) ? 1 : 0;
// Absolute difference atmost K
if (Math.abs(i - previous) <= K)
res += possibleNumbers(pos + 1, i,
new_tight, 1,
N, K);
}
}
// Store the solution
// to this subproblem
dp[pos][previous][tight][start] = res;
return dp[pos][previous][tight][start];
}
// Driver code
public static void main(String[] args)
{
String N = "20";
int K = 2;
// Initialising the
// table with -1
for(int i = 0; i < 1002; i++)
for(int j = 0; j < 10; j++)
for(int k = 0; k < 2; k++)
for(int l = 0; l < 2; l++)
dp[i][j][k][l] = -1;
// Function call
System.out.print(possibleNumbers(0, 0, 1, 0,
N, K) + "\n");
}
}
// This code is contributed by Princi Singh
Python3
# Python3 program to get the count of
# numbers upto N having absolute
# difference at most K between any
# two adjacent digits
# Table to store solution
# of each subproblem
dp = [[[[ -1 for i in range(2)]
for j in range(2)]
for i in range(10)]
for j in range(1002)]
# Function to calculate
# all possible numbers
def possibleNumber(pos, previous, tight,
start, N, K):
# Check if position reaches end
# that is equal to length of N
if(pos == len(N)):
return 1
# Check if the result is
# already computed
# simply return it
if(dp[pos][previous][tight][start] != -1):
return dp[pos][previous][tight][start]
res = 0
# Maximum limit upto which we can place
# digit. If tight is false, means number has
# already become smaller so we can place
# any digit, otherwise N[pos]
if(tight):
upper_limit = ord(N[pos]) - ord('0')
else:
upper_limit = 9
# Chekc if start is false the number
# has not started yet
if(not start):
# Check if we do not start
# the number at pos
# then recur forward
res = possibleNumber(pos + 1, previous,
False, False, N, K)
# If we start the number
# we can place any digit
# from 1 to upper_limit
for i in range(1, upper_limit + 1):
# Finding the new tight
if(tight and i == upper_limit):
new_tight = 1
else:
new_tight = 0
res += possibleNumber(pos + 1, i,
new_tight,
True, N, K)
# Condition if the number
# has already started
else:
# We can place digit upto
# upperbound & absolute
# difference with previous
# digit much be atmost K
for i in range(upper_limit + 1):
if(tight and i == upper_limit):
new_tight = 1
else:
new_tight = 0
# Absolute difference atmost K
if(abs(i - previous) <= K):
res += possibleNumber(pos + 1, i,
new_tight,
True, N, K)
# Store the solution to this subproblem
dp[pos][previous][tight][start] = res
return dp[pos][previous][tight][start]
# Driver code
if __name__ == '__main__':
N = "20"
K = 2
# Function call
print(possibleNumber(0, 0, True,
False, N, K))
# This code is contributed by Shivam Singh
C#
// C# program to get the count
// of numbers upto N having
// absolute difference at most K
// between any two adjacent digits
using System;
class GFG{
// Table to store solution
// of each subproblem
static int [,,,]dp = new int[1002, 10, 2, 2];
// Function to calculate
// all possible numbers
static int possibleNumbers(int pos, int previous,
int tight, int start,
String N, int K)
{
// Check if position reaches end
// that is equal to length of N
if (pos == N.Length)
return 1;
// Check if the result is already
// computed simply return it
if (dp[pos, previous, tight, start] != -1)
return dp[pos, previous, tight, start];
int res = 0;
// Maximum limit upto which we can
// place digit. If tight is false,
// means number has already become
// smaller so we can place
// any digit, otherwise N[pos]
int upper_limit = (tight == 1) ?
(N[pos] - '0') : 9;
int new_tight;
// Check if start is false the number
// has not started yet
if (start == 0)
{
// Check if we do not start
// the number at pos
// then recur forward
res = possibleNumbers(pos + 1, previous,
0, 0, N, K);
// If we start the number
// we can place any digit
// from 1 to upper_limit
for(int i = 1; i <= upper_limit; i++)
{
// Finding the new tight
new_tight = (tight > 0 &&
i == upper_limit) ? 1 : 0;
res += possibleNumbers(pos + 1, i,
new_tight,
1, N, K);
}
}
// Condition if the number
// has already started
else
{
// We can place digit upto
// upperbound & absolute difference
// with previous digit much
// be atmost K
for(int i = 0; i <= upper_limit; i++)
{
new_tight = (tight > 0 &&
i == upper_limit) ? 1 : 0;
// Absolute difference atmost K
if (Math.Abs(i - previous) <= K)
res += possibleNumbers(pos + 1, i,
new_tight, 1,
N, K);
}
}
// Store the solution
// to this subproblem
dp[pos, previous, tight, start] = res;
return dp[pos, previous, tight, start];
}
// Driver code
public static void Main(String[] args)
{
String N = "20";
int K = 2;
// Initialising the
// table with -1
for(int i = 0; i < 1002; i++)
for(int j = 0; j < 10; j++)
for(int k = 0; k < 2; k++)
for(int l = 0; l < 2; l++)
dp[i, j, k, l] = -1;
// Function call
Console.Write(possibleNumbers(0, 0, 1, 0,
N, K) + "\n");
}
}
// This code is contributed by amal kumar choubey
输出:
15
时间复杂度: O(D * 10 * 2 * 2 * 10),考虑到N具有D位。