Given an array, arr[] of size N, the task is to find the length of the longest increasing prime subsequence possible by performing the following operations.
- If arr[i] is already a prime number, no need to update arr[i].
- Update non-prime arr[i] to the closest prime number less than arr[i].
- Update non-prime arr[i] to the closest prime number greater than arr[i].
Examples:
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
Naive Approach: The simplest approach is to update all the elements of the given array to either it’s closest smaller prime number or it’s closest greater prime number and then generate all possible subsequence of the given array and print the length of the longest subsequence consisting of prime numbers in increasing order.
Time Complexity: O(2N)
Auxiliary Space: O(N)
Efficient Approach: The idea is to use Dynamic programming approach to optimize the above approach. This problem is a basic variation of the Longest Increasing Prime Subsequence (LIPS) problem. Follow the steps below to solve the problem.
- Initialize a 2-dimensional array, say dp[][] of size N * 2, where dp[i][0] stores the length of the longest increasing prime subsequence by choosing the closest prime number smaller than arr[i] at ith index and dp[i][1] stores the length of the longest increasing prime subsequence by choosing the closest prime number greater than or equal to arr[i] at ithindex. Below are the recurrence relation:
- 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)
- Use sieve of Eratosthenes to efficiently compute the prime numbers.
- Traverse the array arr[] and for each index, i, update arr[i] to the closest prime number of arr[i].
- For each index i, find the length of the longest increasing prime subsequence ending at i, optimally.
- Finally, return the length of the longest increasing prime subsequence.
Below is the implementation of the above approach:
// C++ code for the above approach #include <bits/stdc++.h> using namespace std;
// Stores the closest prime number for each array element set< int > st;
// Function to find the length of longest increasing prime // subsequence int LIPS( int arr[], int N)
{ // Base case
if (N == 0)
return 0;
int dp[N + 1][2];
// Store the length of the longest increasing prime
// subsequence
int max_subsequence = 0;
for ( int i = 0; i < N; 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
auto option1 = st.lower_bound(arr[j]);
// Store closest prime number greater or equal
auto option2 = st.upper_bound(arr[j]);
// Recurrence relation
if (option1 != st.begin()
&& *(--option1)
< *(st.lower_bound(arr[i])))
dp[i][0] = max(dp[i][0], dp[j][0] + 1);
if (option2 != st.end()
&& *option2 < *(st.lower_bound(arr[i])))
dp[i][0] = max(dp[i][0], dp[j][1] + 1);
// Fill the value of dp[i][1]
if (option1 != st.begin()
&& *(--option1)
< *(st.upper_bound(arr[i])))
dp[i][1] = max(dp[i][1], dp[j][0] + 1);
if (option2 != st.end()
&& *option2 < *(st.upper_bound(arr[i])))
dp[i][1] = max(dp[i][1], dp[j][1] + 1);
}
// Store the length of the longest increasing prime
// subsequence
max_subsequence = max(max_subsequence, dp[i][0]);
max_subsequence = max(max_subsequence, dp[i][1]);
}
return max_subsequence/2;
} // Function to generate all prime numbers void prime_sieve()
{ // Store all prime numbers
bool primes[1000000 + 5];
// Consider all prime numbers to be true initially
fill(primes, primes + 1000000 + 5, 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
st.insert(2);
// Add all primes to the set
for ( int i = 3; i <= 1000000; i += 2)
if (primes[i])
st.insert(i);
} // Driver Code int main()
{ int N = 6;
int arr[] = { 6, 7, 8, 9, 10, 11 };
prime_sieve();
cout << LIPS(arr, N) << endl;
return 0;
} // This code is contributed by lokeshpotta20. |
// Java Program to implement // the above approach import java.util.*;
public class Main {
// Stores the closest prime
// number for each array element
static TreeSet<Integer> 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));
}
} |
# Python Program to implement # the above approach # Stores the closest prime # number for each array element st = set ()
# Function to find the length of longest # increasing prime subsequence def LIPS(arr, N):
# Base case
if N = = 0 :
return 0
dp = [[ 0 , 1 ] for i in range (N)]
# Store the length of the longest
# increasing prime subsequence
max_subsequence = 0
for i in range (N):
# Store the length of LIPS
# by choosing the closest prime
# number smaller than arr[i]
if arr[i] > = 2 :
dp[i][ 0 ] = 1
else :
dp[i][ 0 ] = 0
# Store the length of longest LIPS
# by choosing the closest prime
# number greater than arr[i]
for j in range (i):
# Store closest smaller
# prime number
option1 = list ( filter ( lambda x: x < arr[i], st))
option2 = list ( filter ( lambda x: x < arr[i], st))
# Recurrence relation
# Fill the value of dp[i][0]
if len (option1) > 0 and option1[ - 1 ] < arr[i]:
dp[i][ 0 ] = max (dp[i][ 0 ], dp[j][ 0 ] + 1 )
if len (option2) > 0 and option2[ - 1 ] < arr[i]:
dp[i][ 0 ] = max (dp[i][ 0 ], dp[j][ 1 ] + 1 )
# Fill the value of dp[i][1]
if len (option1) > 0 and option1[ - 1 ] < arr[i]:
dp[i][ 1 ] = max (dp[i][ 1 ], dp[j][ 0 ] + 1 )
if len (option2) > 0 and option2[ - 1 ] < arr[i]:
dp[i][ 1 ] = max (dp[i][ 1 ], dp[j][ 1 ] + 1 )
# Store the length of the longest
# increasing prime subsequence
max_subsequence = max (max_subsequence, dp[i][ 0 ])
max_subsequence = max (max_subsequence, dp[i][ 1 ])
return int (max_subsequence / 2 )
# Function to generate all prime numbers def primeSieve():
# Store all prime numbers
# Consider all prime numbers
# to be true initially
primes = [ True for i in range ( 1000001 + 5 )]
# Mark 0 and 1 non-prime
primes[ 0 ] = primes[ 1 ] = False
# Set all even numbers to
# non-prime
for i in range ( 4 , 1000001 , 2 ):
primes[i] = False
for i in range ( 3 , 1000001 , 2 ):
# If current element is prime
if primes[i]:
# Update all its multiples
# as non-prime
for j in range ( 2 * i, 1000001 , i):
primes[j] = False
# Mark 2 as prime
st.add( 2 )
# Add all primes to the set
for i in range ( 3 , 1000001 , 2 ):
if primes[i]:
st.add(i)
# Driver Code primeSieve() N = 6
arr = [ 6 , 7 , 8 , 9 , 10 , 11 ]
print (LIPS(arr, N))
|
using System;
using System.Linq;
using System.Collections.Generic;
class MainClass {
// Stores the closest prime number for each array element
static SortedSet< int > st = new SortedSet< int >();
// Function to find the length of longest increasing prime
// subsequence
static int LIPS( int [] arr, int N) {
// Base case
if (N == 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 < N; 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
var option1 = st.GetViewBetween(arr[j],
int .MaxValue).FirstOrDefault();
// Store closest prime number greater or equal
var option2 = st.GetViewBetween(arr[j],
int .MaxValue).Skip(1).FirstOrDefault();
// Recurrence relation
if (option1 < st.GetViewBetween(arr[i], int .MaxValue).First())
dp[i, 0] = Math.Max(dp[i, 0], dp[j, 0] + 1);
if (option2 < st.GetViewBetween(arr[i], int .MaxValue).First())
dp[i, 0] = Math.Max(dp[i, 0], dp[j, 1] + 1);
// Fill the value of dp[i][1]
if (option1 < st.GetViewBetween(arr[i],
int .MaxValue).Skip(1).First())
dp[i, 1] = Math.Max(dp[i, 1], dp[j, 0] + 1);
if (option2 < st.GetViewBetween(arr[i],
int .MaxValue).Skip(1).First())
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
static void prime_sieve() {
// Store all prime numbers
bool [] primes = new bool [1000000 + 5 + 1];
// Consider all prime numbers to be true initially
for ( int i = 0; i <= 1000000 + 5; i++)
primes[i] = 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
st.Add(2);
// Add all primes to the set
for ( int i = 3; i <= 1000000; i += 2)
if (primes[i])
st.Add(i);
}
// Driver Code
public static void Main( string [] args) {
int N = 6;
int [] arr = { 6, 7, 8, 9, 10, 11 };
prime_sieve();
Console.WriteLine(LIPS(arr, N));
}
} |
// Javascript Program to implement // the above approach // Stores the closest prime // number for each array element let st = new Set();
// Function to find the length of longest // increasing prime subsequence function LIPS(arr, N) {
// Base case
if (N === 0) return 0;
let dp = new Array(N);
for (let i = 0; i < N; i++) {
dp[i] = [0, 1];
}
// Store the length of the longest
// increasing prime subsequence
let max_subsequence = 0;
for (let i = 0; i < N; 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]
for (let j = 0; j < i; j++) {
// Store closest smaller
// prime number
let option1 = Array.from(st).filter((x) => x < arr[i]);
let option2 = Array.from(st).filter((x) => x < arr[i]);
// Recurrence relation
// Fill the value of dp[i][0]
if (option1.length > 0 && option1[option1.length - 1] < arr[i])
dp[i][0] = Math.max(dp[i][0], dp[j][0] + 1);
if (option2.length > 0 && option2[option2.length - 1] < arr[i])
dp[i][0] = Math.max(dp[i][0], dp[j][1] + 1);
// Fill the value of dp[i][1]
if (option1.length > 0 && option1[option1.length - 1] < arr[i])
dp[i][1] = Math.max(dp[i][1], dp[j][0] + 1);
if (option2.length > 0 && option2[option2.length - 1] < 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 Math.floor(max_subsequence / 2);
} // Function to generate all prime numbers function primeSieve() {
// Store all prime numbers
// Consider all prime numbers
// to be true initially
let primes = new Array(1000000 + 5).fill( true );
// Mark 0 and 1 non-prime
primes[0] = primes[1] = false ;
// Set all even numbers to
// non-prime
for (let i = 4; i <= 1000000; i += 2) primes[i] = false ;
for (let i = 3; i <= 1000000; i += 2) {
// If current element is prime
if (primes[i]) {
// Update all its multiples
// as non-prime
for (let j = 2 * i; j <= 1000000; j += i) primes[j] = false ;
}
}
// Mark 2 as prime
st.add(2);
// Add all primes to the set
for (let i = 3; i <= 1000000; i += 2) {
if (primes[i]) {
st.add(i);
}
}
} // Driver Code primeSieve(); let N = 6; let arr = [6, 7, 8, 9, 10, 11]; console.log(LIPS(arr, N)); // This code is contributed by Shivhack999 |
3
Time Complexity: O(N2logN)
Auxiliary Space: O(N)