📌  相关文章
📜  具有单位 GCD 的子序列的最小长度

📅  最后修改于: 2021-09-17 07:19:19             🧑  作者: Mango

给定一个由N 个正整数组成的数组arr[] 。任务是找到最短子序列的长度,使得子序列的 GCD 为 1。如果没有子序列的 GCD 为 1,则打印“-1 ”。

例子:

朴素的方法:想法是生成给定数组的所有可能子序列,并打印 GCD 为 1 且具有最小长度的子序列的长度。如果没有子序列具有 GCD 1,则打印“-1 ”。

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

有效的方法:解决这个问题有两个关键观察:

  1. 只有当两个数的质因数不同时,它们的 GCD 才会等于 1。
  2. 任何小于10 9 的正数最多可以有 9 个质因数。
    例如2×3×5×7×11×13×17×19×23 = 22, 30, 92, 870. 如果我们将此数乘以下一个质数,即 29,它将大于 10^ 9.

请按照以下步骤解决问题:

  1. 将数字表示为其质因数的乘积。由于我们最多有 9 个质因子,因此我们可以使用 Bitmask 的概念来存储数字的状态。
    例如,12 的质因数是 2 和 3。这可以用二进制表示为 11(忽略前面的零),这意味着这个数字有两个质因数。
  2. 对于输入数组中的每个数字,检查是否有任何其他数字设置了相应的位。这可以使用按位与运算来实现。这个操作的结果是我们解空间的另一种状态。
  3. 现在使用动态规划的概念来记住状态。这个想法是使用一个数组来存储解空间的状态。这是有效的,因为一次只能设置 9 位,并且大小为 1024 的数组可以捕获解空间的所有状态。
  4. 每个状态都使用动态规划来存储到达该状态的最短路径。
  5. 如果任意两个状态的 Bitwise AND 等于0 ,则 GCD 等于1 ,即如果有可能从当前状态到达状态0 ,那么它将具有最小长度的子序列并打印length 否则打印“-1”

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
 
// Function that finds the prime
// factors of a number
vector findPrimeFactors(int n)
{
    // To store the prime factor
    vector primeFactors(9, 0);
 
    int j = 0;
 
    // 2s that divide n
    if (n % 2 == 0) {
        primeFactors[j++] = 2;
        while (n % 2 == 0)
            n >>= 1;
    }
 
    // N must be odd at this point
    // Skip one element
    for (int i = 3;
         i * i <= n; i += 2) {
 
        if (n % i == 0) {
 
            // Update the prime factor
            primeFactors[j++] = i;
            while (n % i == 0)
                n /= i;
        }
    }
 
    // If n is a prime number
    // greater than 2
    if (n > 2)
        primeFactors[j++] = n;
     
    vector PrimeFactors(j);
     
    for(int i = 0; i < j; i++)
    {
        PrimeFactors[i] = primeFactors[i];
    }
     
    return PrimeFactors;
}
 
// Function that finds the shortest
// subsequence
void findShortestSubsequence(vector &dp, vector a,
                        int index, vector primeFactors)
{
    int n = a.size();
 
    for (int j = index; j < n; j++) {
        int bitmask = 0;
 
        for (int p = 0;
             p < primeFactors.size(); p++) {
 
            // Check if the prime factor
            // of first number, is also
            // the prime factor of the
            // rest numbers in array
            if ((a[j] % primeFactors[p]) == 0) {
 
                // Set corresponding bit
                // of prime factor to 1,
                // it means both these
                // numbers have the
                // same prime factor
                bitmask ^= (1 << p);
            }
        }
 
        for (int i = 0; i < dp.size(); i++) {
 
            // If no states encountered
            // so far continue for this
            // combination of bits
            if (dp[i] == n + 1)
                continue;
 
            // Update this state with
            // minimum ways to reach
            // this state
            dp[bitmask & i]
                = min(dp[bitmask & i],
                           dp[i] + 1);
        }
    }
}
 
// Function that print the minimum
// length of subsequence
void printMinimumLength(vector a)
{
    int Min = a.size() + 1;
 
    for (int i = 0; i < a.size() - 1; i++) {
 
        // Find the prime factors of
        // the first number
        vector primeFactors
            = findPrimeFactors(a[i]);
 
        int n = primeFactors.size();
     
        // Initialize the array with
        // maximum steps, size of the
        // array + 1 for instance
        vector dp(1 << n, a.size() + 1);
 
        // Express the prime factors
        // in bit representation
 
        // Total number of set bits is
        // equal to the total number
        // of prime factors
        int setBits = (1 << n) - 1;
 
        // Indicates there is one
        // way to reach the number
        // under consideration
        dp[setBits] = 1;
        findShortestSubsequence(dp, a, i + 1,
                                primeFactors);
 
        // State 0 corresponds
        // to gcd of 1
        Min = min(dp[0], Min);
    }
 
    // If not found such subsequence
    // then print "-1"
    if (Min == (a.size() + 1))
        cout << -1 << endl;
 
    // Else print the length
    else
        cout << Min << endl;
}
 
// Driver code
int main()
{
    // Given array arr[]
    vector arr = { 2, 6, 12, 3 };
     
    // Function Call
    printMinimumLength(arr);
    return 0;
}
 
// This code is contributed by divyeshrabadiya07


Java
// Java program for the above approach
import java.io.*;
import java.util.*;
 
class GFG {
 
    // Function that finds the prime
    // factors of a number
    private static int[] findPrimeFactors(int n)
    {
        // To store the prime factor
        int[] primeFactors = new int[9];
 
        int j = 0;
 
        // 2s that divide n
        if (n % 2 == 0) {
            primeFactors[j++] = 2;
            while (n % 2 == 0)
                n >>= 1;
        }
 
        // N must be odd at this point
        // Skip one element
        for (int i = 3;
             i * i <= n; i += 2) {
 
            if (n % i == 0) {
 
                // Update the prime factor
                primeFactors[j++] = i;
                while (n % i == 0)
                    n /= i;
            }
        }
 
        // If n is a prime number
        // greater than 2
        if (n > 2)
            primeFactors[j++] = n;
 
        return Arrays.copyOfRange(primeFactors, 0, j);
    }
 
    // Function that finds the shortest
    // subsequence
    private static void
    findShortestSubsequence(int[] dp, int[] a,
                            int index,
                            int[] primeFactors)
    {
        int n = a.length;
 
        for (int j = index; j < n; j++) {
            int bitmask = 0;
 
            for (int p = 0;
                 p < primeFactors.length; p++) {
 
                // Check if the prime factor
                // of first number, is also
                // the prime factor of the
                // rest numbers in array
                if (a[j] % primeFactors[p] == 0) {
 
                    // Set corresponding bit
                    // of prime factor to 1,
                    // it means both these
                    // numbers have the
                    // same prime factor
                    bitmask ^= (1 << p);
                }
            }
 
            for (int i = 0;
                 i < dp.length; i++) {
 
                // If no states encountered
                // so far continue for this
                // combination of bits
                if (dp[i] == n + 1)
                    continue;
 
                // Update this state with
                // minimum ways to reach
                // this state
                dp[bitmask & i]
                    = Math.min(dp[bitmask & i],
                               dp[i] + 1);
            }
        }
    }
 
    // Function that print the minimum
    // length of subsequence
    private static void
    printMinimumLength(int[] a)
    {
        int min = a.length + 1;
 
        for (int i = 0;
             i < a.length - 1; i++) {
 
            // Find the prime factors of
            // the first number
            int[] primeFactors
                = findPrimeFactors(a[i]);
 
            int n = primeFactors.length;
 
            int[] dp = new int[1 << n];
 
            // Initialize the array with
            // maximum steps, size of the
            // array + 1 for instance
            Arrays.fill(dp, a.length + 1);
 
            // Express the prime factors
            // in bit representation
 
            // Total number of set bits is
            // equal to the total number
            // of prime factors
            int setBits = (1 << n) - 1;
 
            // Indicates there is one
            // way to reach the number
            // under consideration
            dp[setBits] = 1;
            findShortestSubsequence(dp, a, i + 1,
                                    primeFactors);
 
            // State 0 corresponds
            // to gcd of 1
            min = Math.min(dp[0], min);
        }
 
        // If not found such subsequence
        // then print "-1"
        if (min == a.length + 1)
            System.out.println(-1);
 
        // Else print the length
        else
            System.out.println(min);
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        // Given array arr[]
        int[] arr = { 2, 6, 12, 3 };
 
        // Function Call
        printMinimumLength(arr);
    }
}


Python3
# Python3 program for the above approach
 
# Function that finds the prime
# factors of a number
def findPrimeFactors(n):
     
    # To store the prime factor
    primeFactors = [0 for i in range(9)]
 
    j = 0
 
    # 2s that divide n
    if (n % 2 == 0):
        primeFactors[j] = 2
        j += 1
         
        while (n % 2 == 0):
            n >>= 1
 
    # N must be odd at this point
    # Skip one element
    i = 3
    while (i * i <= n):
        if (n % i == 0):
             
            # Update the prime factor
            primeFactors[j] = i
            j += 1
             
            while(n % i == 0):
                n //= i
                 
        i += 2
 
    # If n is a prime number
    # greater than 2
    if (n > 2):
        primeFactors[j] = n
        j += 1
 
    for i in range(0, j + 1):
        primeFactors[i] = 0
         
    return primeFactors
 
# Function that finds the shortest
# subsequence
def findShortestSubsequence(dp, a, index,
                            primeFactors):
    n = len(a)
 
    for j in range(index, n):
        bitmask = 0
 
        for p in range(len(primeFactors)):
             
            # Check if the prime factor
            # of first number, is also
            # the prime factor of the
            # rest numbers in array
            if (primeFactors[p] != 0 and
                a[j] % primeFactors[p] == 0):
                     
                # Set corresponding bit
                # of prime factor to 1,
                # it means both these
                # numbers have the
                # same prime factor
                bitmask ^= (1 << p)
 
        for i in range(len(dp)):
             
            # If no states encountered
            # so far continue for this
            # combination of bits
            if (dp[i] == n + 1):
                continue
 
            # Update this state with
            # minimum ways to reach
            # this state
            dp[bitmask & i] = min(dp[bitmask & i],
                                  dp[i] + 1)
 
# Function that print the minimum
# length of subsequence
def printMinimumLength(a):
     
    mn = len(a) + 1
 
    for i in range(len(a) - 1):
 
        # Find the prime factors of
        # the first number
        primeFactors = findPrimeFactors(a[i])
 
        n = len(primeFactors)
 
        dp = [0 for i in range(1 << n)]
 
        # Initialize the array with
        # maximum steps, size of the
        # array + 1 for instance
        dp = [len(a) + 1 for i in range(len(dp))]
 
        # Express the prime factors
        # in bit representation
 
        # Total number of set bits is
        # equal to the total number
        # of prime factors
        setBits = (1 << n) - 1
 
        # Indicates there is one
        # way to reach the number
        # under consideration
        dp[setBits] = 1
         
        findShortestSubsequence(dp, a, i + 1,
                                primeFactors)
 
        # State 0 corresponds
        # to gcd of 1
        mn = min(dp[0], mn)
 
    # If not found such subsequence
    # then print "-1"
    if (mn == len(a) + 1):
        print(-1)
 
    # Else print the length
    else:
        print(mn)
 
# Driver Code
if __name__ == '__main__':
     
    # Given array arr[]
    arr = [ 2, 6, 12, 3 ]
 
    # Function Call
    printMinimumLength(arr)
 
# This code is contributed by bgangwar59


C#
// C# program for
// the above approach
using System;
class GFG{
 
// Function that finds the prime
// factors of a number
private static int[] findPrimeFactors(int n)
{
  // To store the prime factor
  int[] primeFactors = new int[9];
 
  int j = 0;
 
  // 2s that divide n
  if (n % 2 == 0)
  {
    primeFactors[j++] = 2;
    while (n % 2 == 0)
      n >>= 1;
  }
 
  // N must be odd at this point
  // Skip one element
  for (int i = 3;
           i * i <= n; i += 2)
  {
    if (n % i == 0)
    {
      // Update the prime factor
      primeFactors[j++] = i;
      while (n % i == 0)
        n /= i;
    }
  }
 
  // If n is a prime number
  // greater than 2
  if (n > 2)
    primeFactors[j++] = n;
   
  int []temp = new int[j];
  Array.Copy(primeFactors, temp, j);
  return temp;
}
 
// Function that finds the shortest
// subsequence
private static void findShortestSubsequence(int[] dp, int[] a,
                                            int index,
                                            int[] primeFactors)
{
  int n = a.Length;
 
  for (int j = index; j < n; j++)
  {
    int bitmask = 0;
 
    for (int p = 0;
             p < primeFactors.Length; p++)
    {
      // Check if the prime factor
      // of first number, is also
      // the prime factor of the
      // rest numbers in array
      if (a[j] % primeFactors[p] == 0)
      {
        // Set corresponding bit
        // of prime factor to 1,
        // it means both these
        // numbers have the
        // same prime factor
        bitmask ^= (1 << p);
      }
    }
 
    for (int i = 0;
             i < dp.Length; i++)
    {
      // If no states encountered
      // so far continue for this
      // combination of bits
      if (dp[i] == n + 1)
        continue;
 
      // Update this state with
      // minimum ways to reach
      // this state
      dp[bitmask & i] = Math.Min(dp[bitmask & i],
                                 dp[i] + 1);
    }
  }
}
 
// Function that print the minimum
// length of subsequence
private static void printMinimumLength(int[] a)
{
  int min = a.Length + 1;
 
  for (int i = 0;
           i < a.Length - 1; i++)
  {
    // Find the prime factors of
    // the first number
    int[] primeFactors = findPrimeFactors(a[i]);
 
    int n = primeFactors.Length;
 
    int[] dp = new int[1 << n];
 
    // Initialize the array with
    // maximum steps, size of the
    // array + 1 for instance
    for(i = 0; i < dp.Length; i++)
      dp[i] = a.Length + 1;
 
    // Express the prime factors
    // in bit representation
 
    // Total number of set bits is
    // equal to the total number
    // of prime factors
    int setBits = (1 << n) - 1;
 
    // Indicates there is one
    // way to reach the number
    // under consideration
    dp[setBits] = 1;
    findShortestSubsequence(dp, a, i + 1,
                            primeFactors);
 
    // State 0 corresponds
    // to gcd of 1
    min = Math.Min(dp[0], min);
  }
 
  // If not found such subsequence
  // then print "-1"
  if (min == a.Length + 1)
    Console.WriteLine(-1);
 
  // Else print the length
  else
    Console.WriteLine(min);
}
 
// Driver Code
public static void Main(String[] args)
{
  // Given array []arr
  int[] arr = {2, 6, 12, 3};
 
  // Function Call
  printMinimumLength(arr);
}
}
 
// This code is contributed by Rajput-Ji


Javascript


输出
2

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