📌  相关文章
📜  最大化给定数组中最长递增质数子序列的长度

📅  最后修改于: 2021-04-29 04:29:59             🧑  作者: Mango

给定大小为N的数组arr [] ,任务是通过执行以下操作来找到最长的递增质数子序列的长度。

  • 如果arr [i]已经是质数,则无需更新arr [i]
  • 将非素数arr [i]更新为小于arr [i]的最接近素数。
  • 将非素数arr [i]更新为大于arr [i]的最接近素数。

例子:

天真的方法:最简单的方法是将给定数组的所有元素更新为最接近的较小素数或最接近的更大素数,然后生成给定数组的所有可能的子序列,并打印由素数组成的最长子序列的长度数字按升序排列。
时间复杂度: O(2 N )
辅助空间: O(N)

高效方法:想法是使用动态编程方法来优化上述方法。此问题是最长增加质数子序列(LIPS)问题的基本变体。请按照以下步骤解决问题。

  1. 初始化一个二维数组,例如大小为N * 2的dp [] [] ,其中dp [i] [0]通过在i处选择小于arr [i]的最接近质数来存储最长递增质数子序列的长度。 th索引和dp [i] [1]通过选择第i索引处大于或等于arr [i]的最接近素数来存储最长递增素数子序列的长度。以下是递归关系:
  2. 使用Eratosthenes筛子有效地计算素数。
  3. 遍历数组arr [] ,对于每个索引i ,将arr [i]更新为最接近的素数arr [i]
  4. 对于每个索引i ,找到最佳地以i结尾的最长递增质数子序列的长度。
  5. 最后,返回最长的素数子序列的长度。

下面是上述方法的实现:

Java
// Java Program to implement
// the above approach
  
import java.util.*;
  
public class Main {
  
    // Stores the closest prime
    // number for each array element
    static TreeSet set
        = new TreeSet<>();
  
    // Function to find the length of longest
    // increasing prime subsequence
    public static int LIPS(int arr[], int N)
    {
        // Base case
        if (arr.length == 0)
            return 0;
  
        int dp[][] = new int[N + 1][2];
  
        // Store the length of the longest
        // increasing prime subsequence
        int max_subsequence = 0;
        for (int i = 0; i < arr.length;
             i++) {
            // Store the length of LIPS
            // by choosing the closest prime
            // number smaller than arr[i]
            dp[i][0] = (arr[i] >= 2) ? 1 : 0;
  
            // Store the length of longest LIPS
            // by choosing the closest prime
            // number greater than arr[i]
            dp[i][1] = 1;
            for (int j = 0; j < i; j++) {
  
                // Store closest smaller
                // prime number
                Integer option1 = set.floor(arr[j]);
  
                // Store closest prime number
                // greater or equal
                Integer option2 = set.ceiling(arr[j]);
  
                // Recurrence relation
  
                // Fill the value of dp[i][0]
                if (option1 != null
                    && option1 < set.floor(arr[i]))
                    dp[i][0]
                        = Math.max(dp[i][0], dp[j][0] + 1);
  
                if (option2 != null
                    && option2 < set.floor(arr[i]))
                    dp[i][0]
                        = Math.max(dp[i][0], dp[j][1] + 1);
  
                // Fill the value of dp[i][1]
                if (option1 != null
                    && option1 < set.ceiling(arr[i]))
                    dp[i][1]
                        = Math.max(dp[i][0], dp[j][0] + 1);
  
                if (option2 != null
                    && option2 < set.ceiling(arr[i]))
                    dp[i][1]
                        = Math.max(dp[i][1], dp[j][1] + 1);
            }
  
            // Store the length of the longest
            // increasing prime subsequence
            max_subsequence
                = Math.max(max_subsequence, dp[i][0]);
  
            max_subsequence
                = Math.max(max_subsequence, dp[i][1]);
        }
  
        return max_subsequence;
    }
  
    // Function to generate all prime numbers
    public static void prime_sieve()
    {
        // Store all prime numbers
        boolean primes[]
            = new boolean[1000000 + 5];
  
        // Consider all prime numbers
        // to be true initially
        Arrays.fill(primes, true);
  
        // Mark 0 and 1 non-prime
        primes[0] = primes[1] = false;
  
        // Set all even numbers to
        // non-prime
        for (int i = 4; i <= 1000000;
             i += 2)
            primes[i] = false;
  
        for (int i = 3; i <= 1000000;
             i += 2) {
  
            // If current element is prime
            if (primes[i]) {
  
                // Update all its multiples
                // as non-prime
                for (int j = 2 * i; j <= 1000000;
                     j += i)
                    primes[j] = false;
            }
        }
  
        // Mark 2 as prime
        set.add(2);
  
        // Add all primes to the set
        for (int i = 3; i <= 1000000;
             i += 2)
            if (primes[i])
                set.add(i);
    }
  
    // Driver Code
    public static void main(String args[])
    {
        int N = 6;
        int arr[] = { 6, 7, 8, 9, 10, 11 };
  
        prime_sieve();
  
        System.out.println(LIPS(arr, N));
    }
}


输出:
3

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