Maximize length of longest increasing prime subsequence from the given array

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.

  1. 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 ith index. 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)

  2. Use sieve of Eratosthenes to efficiently compute the prime numbers.
  3. Traverse the array arr[] and for each index, i, update arr[i] to the closest prime number of arr[i].
  4. For each index i, find the length of the longest increasing prime subsequence ending at i, optimally.
  5. Finally, return the length of the longest increasing prime subsequence.

Below is the implementation of the above approach:

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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));
    }
}

chevron_right


Output:

3

Time Complexity: O(N2logN)
Auxiliary Space: O(N)

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.