给定一个大小为N的数组arr[] ,任务是通过执行以下操作找到可能的最长递增素数子序列的长度。
- 如果arr[i]已经是质数,则无需更新arr[i] 。
- 将非素数arr[i]更新为小于arr[i]的最接近素数。
- 将非素数arr[i]更新为最接近的大于arr[i] 的素数。
例子:
Input: arr[] = {8, 6, 9, 2, 5}
Output: 2
Explanation:
Possible rearrangements of the array are: {{7, 5, 2, 5}, {7, 7, 2, 5}, {11, 5, 2, 5}, {1, 7, 2, 5}}.
Therefore, the length of the longest increasing prime subsequence = 2.
Input: arr[] = {27, 38, 43, 68, 83, 12, 69, 12}
Output : 5
朴素的方法:最简单的方法是将给定数组的所有元素更新为其最接近的较小素数或最接近的较大素数,然后生成给定数组的所有可能子序列并打印由素数组成的最长子序列的长度数字按升序排列。
时间复杂度: O(2 N )
辅助空间: O(N)
Efficient Approach:思路是使用动态规划的方式来优化上面的方式。此问题是最长递增素数子序列 (LIPS) 问题的基本变体。请按照以下步骤解决问题。
- 初始化一个二维数组,比如大小为N * 2 的dp[][] ,其中dp[i][0]通过在i处选择小于arr[i]的最接近素数来存储最长递增素数子序列的长度th index 和dp[i][1]通过在第i个索引处选择大于或等于 arr[i] 的最接近素数来存储最长递增素数子序列的长度。下面是递归关系:
- If closest smaller prime number to arr[j] < closest smaller prime number to arr[i]: dp[i][0] = 1 + dp[j][0]
- If closest prime number greater than or equal to arr[j] < closest smaller prime number to arr[i]: dp[i][0] = max(dp[i][0], 1 + dp[j][1])
- If closest smaller prime number to arr[j] < closest smaller prime number to arr[i]: dp[i][1] = 1 + dp[j][0]
- If closest greater or equal prime number to arr[j] < closest prime number greater than or equal to arr[i]: dp[i][1] = max(dp[i][1], 1 + dp[j][1])
Here the value of j = 0, 1, …, (i-1)
- 使用 Eratosthenes 筛法有效地计算素数。
- 遍历数组arr[] ,对于每个索引i ,将arr[i]更新为最接近的arr[i]素数。
- 对于每个索引i ,最佳地找到以i结尾的最长递增素数子序列的长度。
- 最后,返回最长递增素数子序列的长度。
下面是上述方法的实现:
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 现场工作专业课程和学生竞争性编程现场课程。