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

📅  最后修改于: 2021-09-22 09:59:03             🧑  作者: Mango

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

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

例子:

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

Efficient Approach:思路是使用动态规划的方式来优化上面的方式。此问题是最长递增素数子序列 (LIPS) 问题的基本变体。请按照以下步骤解决问题。

  1. 初始化一个二维数组,比如大小为N * 2 的dp[][] ,其中dp[i][0]通过在i处选择小于arr[i]的最接近素数来存储最长递增素数子序列的长度th index 和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)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程