📜  计算给定范围内相邻数字不互质的数字

📅  最后修改于: 2021-09-22 09:47:17             🧑  作者: Mango

给定一个整数N ,任务是打印范围[1, N] 中相邻数字不是互质的计数数字。

例子:

朴素方法:解决问题的最简单方法是迭代范围1N ,对于范围内的每个数字,检查其相邻数字的 GCD 是否等于1并相应地更新答案。

时间复杂度: O(NlogN)
辅助空间: O(1)

高效方法:上述方法也可以通过使用动态规划进行优化,因为它具有重叠的子问题和最优子结构。子问题可以使用记忆存储在dp[][][][] 表中,其中dp[i][bound][prev][allZeros]存储从第 i 个位置到结尾的答案,其中bound是一个布尔变量确保数字不超过Nprev存储选择的前一个数字,allZeros是一个布尔变量,用于检查到目前为止选择的所有数字是否为0

  1. 通过执行以下步骤定义递归函数noncoprimeCount(i, bound, prev, allZeros)
    1. 将限制N转换为字符串,以便它仅在字符串的长度上迭代,而不是在N的实际限制上迭代
    2. 检查基本情况,即如果整个字符串被完全遍历(i == N) ,则返回1作为范围[1, N] 中的有效数字已构造。
    3. 如果已经计算了状态dp[i][bound][previous][allZeros] 的结果,则返回存储在dp[i][bound][previous][allZeros] 中的值。
    4. 在当前位置‘i’可以放置 [0, 9] 中任何数字。放置数字时,请借助变量bound确保数字不超过“R” 。还要检查当前数字和前一个数字(存储在prev 中)的GCD是否大于 1。这里有两个边缘情况:
      1. 如果当前索引为 0,则将任何数字放在第一位。
      2. 如果到目前为止填充的所有数字都是零,即allZeros为真,那么尽管GCD (0, 1) = 1 ,但将 1 放在当前位置是有效的,因为它是最高有效数字。然后将allZeros设置为false
    5. 在当前位置放置一个有效数字后,为索引 (i + 1) 处的元素递归调用noncoprimeCount函数。
    6. 返回所有可能的有效数字位置的总和作为答案。
  • 完成上述步骤后,打印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)