给定一个整数N ,任务是打印范围[1, N] 中相邻数字不是互质的计数数字。
Two numbers A and B are said to be co-prime if the GCD of the two numbers is 1.
例子:
Input: N = 30
Output: 15
Explanation: The numbers from [1, 30] which have non co-prime adjacent digits are {1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 22, 24, 26, 28, 30}.
Input: N = 10000
Output: 1361
朴素方法:解决问题的最简单方法是迭代范围1到N ,对于范围内的每个数字,检查其相邻数字的 GCD 是否等于1并相应地更新答案。
时间复杂度: O(NlogN)
辅助空间: O(1) 。
高效方法:上述方法也可以通过使用动态规划进行优化,因为它具有重叠的子问题和最优子结构。子问题可以使用记忆存储在dp[][][][] 表中,其中dp[i][bound][prev][allZeros]存储从第 i 个位置到结尾的答案,其中bound是一个布尔变量确保数字不超过N , prev存储选择的前一个数字,allZeros是一个布尔变量,用于检查到目前为止选择的所有数字是否为0 。
- 通过执行以下步骤定义递归函数noncoprimeCount(i, bound, prev, allZeros) 。
- 将限制N转换为字符串,以便它仅在字符串的长度上迭代,而不是在N的实际限制上迭代。
- 检查基本情况,即如果整个字符串被完全遍历(i == N) ,则返回1作为范围[1, N] 中的有效数字已构造。
- 如果已经计算了状态dp[i][bound][previous][allZeros] 的结果,则返回存储在dp[i][bound][previous][allZeros] 中的值。
- 在当前位置‘i’可以放置 [0, 9] 中的任何数字。放置数字时,请借助变量bound确保数字不超过“R” 。还要检查当前数字和前一个数字(存储在prev 中)的GCD是否大于 1。这里有两个边缘情况:
- 如果当前索引为 0,则将任何数字放在第一位。
- 如果到目前为止填充的所有数字都是零,即allZeros为真,那么尽管GCD (0, 1) = 1 ,但将 1 放在当前位置是有效的,因为它是最高有效数字。然后将allZeros设置为false 。
- 在当前位置放置一个有效数字后,为索引 (i + 1) 处的元素递归调用noncoprimeCount函数。
- 返回所有可能的有效数字位置的总和作为答案。
- 完成上述步骤后,打印nocoprimeCount(0)的值作为结果。
下面是上述方法的实现:
C++
#include
using namespace std;
int dp[100][2][10][2];
// Function to count numbers whose
// adjacent digits are not co-prime
int noncoprimeCount(int i, int N, string& S,
bool bound, int prev,
bool allZeros)
{
// Base Case
// If the entire string
// is traversed
if (i == N)
return 1;
int& val = dp[i][bound][prev][allZeros];
// If the subproblem has
// already been computed
if (val != -1)
return val;
int cnt = 0;
for (int j = 0; j <= (bound ? (S[i] - '0') : 9); ++j) {
// A digit can be placed at
// the current position if:
// GCD of current and previous
// digits is not equal to 1
if ((__gcd(j, prev) != 1)
// Current position is 0
|| (i == 0)
// All encountered digits
// until now are 0s
|| allZeros == 1) {
cnt += noncoprimeCount(
i + 1, N, S, bound
& (j == (S[i] - '0')),
j,
allZeros & (j == 0));
}
}
// Return the total
// possible valid numbers
return val = cnt;
}
// Function to count numbers whose
// adjacent digits are not co-prime
void noncoprimeCountUtil(int R)
{
// Convert R to string.
string S = to_string(R);
// Length of string
int N = S.length();
// Initialize dp array with -1
memset(dp, -1, sizeof dp);
// Function call with initial values of
// bound, allZeros, previous as 1, 1, 0
int ans = noncoprimeCount(0, N, S, 1, 0, 1);
// Subtract 1 from the answer, as 0 is included
cout << ans - 1 << endl;
}
// Driver Code
int main()
{
// Input
int N = 10000;
// Function call
noncoprimeCountUtil(N);
return 0;
}
Java
import java.util.*;
class GFG{
static int [][][][]dp = new int[100][2][10][2];
static int __gcd(int a, int b)
{
return b == 0? a:__gcd(b, a % b);
}
// Function to count numbers whose
// adjacent digits are not co-prime
static int noncoprimeCount(int i, int N, char []S,
int bound, int prev,
int allZeros)
{
// Base Case
// If the entire String
// is traversed
if (i == N)
return 1;
int val = dp[i][bound][prev][allZeros];
// If the subproblem has
// already been computed
if (val != -1)
return val;
int cnt = 0;
for (int j = 0; j <= (bound!=0 ? (S[i] - '0') : 9); ++j) {
// A digit can be placed at
// the current position if:
// GCD of current and previous
// digits is not equal to 1
if ((__gcd(j, prev) != 1)
// Current position is 0
|| (i == 0)
// All encountered digits
// until now are 0s
|| allZeros == 1) {
cnt += noncoprimeCount(
i + 1, N, S, bound!=0
& (j == (S[i] - '0'))?1:0,
j,
(allZeros!=0 & (j == 0))?1:0);
}
}
// Return the total
// possible valid numbers
return val = cnt;
}
// Function to count numbers whose
// adjacent digits are not co-prime
static void noncoprimeCountUtil(int R)
{
// Convert R to String.
String S = String.valueOf(R);
// Length of String
int N = S.length();
// Initialize dp array with -1
for (int i = 0; i < 100; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 10; k++)
for (int l = 0; l < 2; l++)
dp[i][j][k][l] = -1;
// Function call with initial values of
// bound, allZeros, previous as 1, 1, 0
int ans = noncoprimeCount(0, N, S.toCharArray(), 1, 0, 1);
// Subtract 1 from the answer, as 0 is included
System.out.print(ans - 1 +"\n");
}
// Driver Code
public static void main(String[] args)
{
// Input
int N = 10000;
// Function call
noncoprimeCountUtil(N);
}
}
// This code contributed by shikhasingrajput
C#
using System;
class GFG{
static int[,,,] dp = new int[100, 2, 10, 2];
static int __gcd(int a, int b)
{
return b == 0 ? a : __gcd(b, a % b);
}
// Function to count numbers whose
// adjacent digits are not co-prime
static int noncoprimeCount(int i, int N, char[] S, int bound,
int prev, int allZeros)
{
// Base Case
// If the entire String
// is traversed
if (i == N)
return 1;
int val = dp[i, bound, prev, allZeros];
// If the subproblem has
// already been computed
if (val != -1)
return val;
int cnt = 0;
for(int j = 0;
j <= (bound != 0 ? (S[i] - '0') : 9); ++j)
{
// A digit can be placed at
// the current position if:
// GCD of current and previous
// digits is not equal to 1
if ((__gcd(j, prev) != 1)
// Current position is 0
|| (i == 0)
// All encountered digits
// until now are 0s
|| allZeros == 1)
{
cnt += noncoprimeCount(i + 1, N, S, bound != 0 &
(j == (S[i] - '0')) ? 1 : 0, j,
(allZeros != 0 & (j == 0)) ? 1 : 0);
}
}
// Return the total
// possible valid numbers
return val = cnt;
}
// Function to count numbers whose
// adjacent digits are not co-prime
static void noncoprimeCountUtil(int R)
{
// Convert R to String.
String S = String.Join("", R);
// Length of String
int N = S.Length;
// Initialize dp array with -1
for(int i = 0; i < 100; i++)
for(int j = 0; j < 2; j++)
for(int k = 0; k < 10; k++)
for(int l = 0; l < 2; l++)
dp[i, j, k, l] = -1;
// Function call with initial values of
// bound, allZeros, previous as 1, 1, 0
int ans = noncoprimeCount(0, N, S.ToCharArray(), 1, 0, 1);
// Subtract 1 from the answer, as 0 is included
Console.Write(ans - 1 + "\n");
}
// Driver Code
public static void Main(String[] args)
{
// Input
int N = 10000;
// Function call
noncoprimeCountUtil(N);
}
}
// This code is contributed by umadevi9616
1361
时间复杂度: O(log 10 N * 2 * 10 * 2 * 10)。当所有数字 [0, 9] 在每次递归调用中迭代时,会出现额外的 10 因子。
辅助空间: O(log 10 N * 2 * 10 * 2)