Length of the longest increasing subsequence which does not contain a given sequence as Subarray

• Difficulty Level : Medium
• Last Updated : 01 Mar, 2021

Given two arrays arr[] and arr1[] of lengths N and M respectively, the task is to find the longest increasing subsequence of array arr[] such that it does not contain array arr1[] as subarray.

Examples:

Input: arr[] = {5, 3, 9, 3, 4, 7}, arr1[] = {3, 3, 7}
Output: 4
Explanation: Required longest increasing subsequence is {3, 3, 4, 7}.

Input: arr[] = {1, 2, 3}, arr1[] = {1, 2, 3}
Output: 2
Explanation: Required longest increasing subsequence is {1, 2}.

Naive Approach: The simplest approach is to generate all possible subsequences of the given array and print the length of the longest subsequence among them, which does not contain arr1[] as subarray.

Time Complexity: O(M * 2N) where N and M are the lengths of the given arrays.
Auxiliary Space: O(M + N)

Efficient Approach: The idea is to use lps[] array generated using KMP Algorithm and Dynamic Programming to find the longest non-decreasing subsequence without any subarray equals to sequence[]. Follow the below steps to solve the problem:

1. Initialize an array dp[N][N][N] where dp[i][j][K] stores the maximum length of non-decreasing subsequence up to index i where j is the index of the previously chosen element in the array arr[] and K denotes that the currently found sequence contains subarray sequence[0, K].
2. Also, generate an array to store the length of the longest prefix suffix using KMP Algorithm.
3. The maximum length can be found by memoizing the below dp transitions:

dp(i, prev, k) = max(1 + dp(i + 1, i, k2), dp(i + 1, prev, k)) where,

• i is the current index.
• prev is the previously chosen element.
• k2 is index of prefix subarray included so far in the currently found sequence which can be found using KMP Array for longest prefix suffix.

Base Case:

• If k is equals to the length of the given sequence, return as the currently found subsequence contains the arr1[].
• If i reaches N, return as no more elements exist.
• If the current state has already been calculated, return.

Below is the implementation of the above approach:

C++

 // C++ program for the above approach #include using namespace std;   // Initialize dp and KMP array int dp; int KMPArray;   // Length of the given sequence[] int m;   // Function to find the max-length // subsequence that does not have // subarray sequence[] int findSubsequence(int a[], int sequence[], int i,                     int prev, int k, int al, int sl) {     // Stores the subsequence     // explored so far     if (k == m)         return INT_MIN;       // Base Case     if (i == al)         return 0;       // Using memoization to     // avoid re-computation     if (prev != -1 && dp[i][prev][k] != -1) {         return dp[i][prev][k];     }       int include = 0;       if (prev == -1 || a[i] >= a[prev]) {         int k2 = k;           // Using KMP array to find         // corresponding index in arr1[]         while (k2 > 0                && a[i] != sequence[k2])             k2 = KMPArray[k2 - 1];           // Incrementing k2 as we are         // including this element in         // the subsequence         if (a[i] == sequence[k2])             k2++;           // Possible answer for         // current state         include = 1                   + findSubsequence(                         a, sequence,                         i + 1, i, k2, al, sl);     }       // Maximum answer for     // current state     int ans = max(         include, findSubsequence(                      a, sequence,                      i + 1, prev, k, al, sl));       // Memoizing the answer for     // the corresponding state     if (prev != -1) {         dp[i][prev][k] = ans;     }       // Return the answer for     // current state     return ans; }   // Function that generate KMP Array void fillKMPArray(int pattern[]) {         // Previous longest prefix suffix     int j = 0;       int i = 1;       // KMPArray is a always 0     KMPArray = 0;       // The loop calculates KMPArray[i]     // for i = 1 to M - 1     while (i < m) {           // If current character is         // same         if (pattern[i] == pattern[j]) {             j++;               // Update the KMP array             KMPArray[i] = j;             i++;         }           // Otherwise         else {               // Update the KMP array             if (j != 0)                 j = KMPArray[j - 1];             else {                 KMPArray[i] = j;                 i++;             }         }     } }   // Function to print the maximum // possible length void printAnswer(int a[], int sequence[], int al, int sl) {       // Length of the given sequence     m = sl;       // Generate KMP array     fillKMPArray(sequence);               // Initialize the states to -1     memset(dp, -1, sizeof(dp));       // Get answer     int ans = findSubsequence(a, sequence, 0, -1, 0, al, sl);       // Print answer     cout << ((ans < 0) ? 0 : ans) << endl; }       // Driver code int main() {         // Given array     int arr[] = { 5, 3, 9, 3, 4, 7 };       // Give arr1     int arr1[] = { 3, 4 };       // Function Call     printAnswer(arr, arr1, 6, 2);     return 0; }   // This code is contributed by divyeshrabadiya07.

Java

 // Java program for the above approach   import java.io.*; import java.util.*;   class GFG {       // Initialize dp and KMP array     static int[][][] dp;     static int[] KMPArray;       // Length of the given sequence[]     static int m;       // Function to find the max-length     // subsequence that does not have     // subarray sequence[]     private static int findSubsequence(         int[] a, int[] sequence,         int i, int prev, int k)     {         // Stores the subsequence         // explored so far         if (k == m)             return Integer.MIN_VALUE;           // Base Case         if (i == a.length)             return 0;           // Using memoization to         // avoid re-computation         if (prev != -1             && dp[i][prev][k] != -1) {             return dp[i][prev][k];         }           int include = 0;           if (prev == -1 || a[i] >= a[prev]) {             int k2 = k;               // Using KMP array to find             // corresponding index in arr1[]             while (k2 > 0                    && a[i] != sequence[k2])                 k2 = KMPArray[k2 - 1];               // Incrementing k2 as we are             // including this element in             // the subsequence             if (a[i] == sequence[k2])                 k2++;               // Possible answer for             // current state             include = 1                       + findSubsequence(                             a, sequence,                             i + 1, i, k2);         }           // Maximum answer for         // current state         int ans = Math.max(             include, findSubsequence(                          a, sequence,                          i + 1, prev, k));           // Memoizing the answer for         // the corresponding state         if (prev != -1) {             dp[i][prev][k] = ans;         }           // Return the answer for         // current state         return ans;     }       // Function that generate KMP Array     private static void     fillKMPArray(int[] pattern)     {         // Previous longest prefix suffix         int j = 0;           int i = 1;           // KMPArray is a always 0         KMPArray = 0;           // The loop calculates KMPArray[i]         // for i = 1 to M - 1         while (i < m) {               // If current character is             // same             if (pattern[i] == pattern[j]) {                 j++;                   // Update the KMP array                 KMPArray[i] = j;                 i++;             }               // Otherwise             else {                   // Update the KMP array                 if (j != 0)                     j = KMPArray[j - 1];                 else {                     KMPArray[i] = j;                     i++;                 }             }         }     }       // Function to print the maximum     // possible length     static void printAnswer(         int a[], int sequence[])     {           // Length of the given sequence         m = sequence.length;           // Initialize kmp array         KMPArray = new int[m];           // Generate KMP array         fillKMPArray(sequence);           // Initialize dp         dp = new int[a.length][a.length][a.length];           // Initialize the states to -1         for (int i = 0; i < a.length; i++)             for (int j = 0; j < a.length; j++)                 Arrays.fill(dp[i][j], -1);           // Get answer         int ans = findSubsequence(             a, sequence, 0, -1, 0);           // Print answer         System.out.println((ans < 0) ? 0 : ans);     }       // Driver code     public static void         main(String[] args) throws Exception     {         // Given array         int[] arr = { 5, 3, 9, 3, 4, 7 };           // Give arr1         int[] arr1 = { 3, 4 };           // Function Call         printAnswer(arr, arr1);     } }

C#

 // C# program for the above approach using System; using System.Collections; using System.Collections.Generic;   class GFG{   // Initialize dp and KMP array static int[,,] dp; static int[] KMPArray;   // Length of the given sequence[] static int m;   // Function to find the max-length // subsequence that does not have // subarray sequence[] private static int findSubsequence(int[] a,                                    int[] sequence,                                    int i, int prev,                                    int k) {           // Stores the subsequence     // explored so far     if (k == m)         return int.MinValue;       // Base Case     if (i == a.Length)         return 0;       // Using memoization to     // avoid re-computation     if (prev != -1 && dp[i, prev, k] != -1)     {         return dp[i, prev, k];     }       int include = 0;       if (prev == -1 || a[i] >= a[prev])     {         int k2 = k;           // Using KMP array to find         // corresponding index in arr1[]         while (k2 > 0 && a[i] != sequence[k2])             k2 = KMPArray[k2 - 1];           // Incrementing k2 as we are         // including this element in         // the subsequence         if (a[i] == sequence[k2])             k2++;           // Possible answer for         // current state         include = 1 + findSubsequence(a, sequence,                                       i + 1, i, k2);     }       // Maximum answer for     // current state     int ans = Math.Max(include,                        findSubsequence(a, sequence,                                        i + 1, prev, k));       // Memoizing the answer for     // the corresponding state     if (prev != -1)     {         dp[i, prev, k] = ans;     }       // Return the answer for     // current state     return ans; }   // Function that generate KMP Array private static void fillKMPArray(int[] pattern) {           // Previous longest prefix suffix     int j = 0;       int i = 1;       // KMPArray is a always 0     KMPArray = 0;       // The loop calculates KMPArray[i]     // for i = 1 to M - 1     while (i < m)     {                   // If current character is         // same         if (pattern[i] == pattern[j])         {             j++;               // Update the KMP array             KMPArray[i] = j;             i++;         }           // Otherwise         else         {                           // Update the KMP array             if (j != 0)                 j = KMPArray[j - 1];             else             {                 KMPArray[i] = j;                 i++;             }         }     } }   // Function to print the maximum // possible length static void printAnswer(int[] a, int[] sequence) {           // Length of the given sequence     m = sequence.Length;       // Initialize kmp array     KMPArray = new int[m];       // Generate KMP array     fillKMPArray(sequence);       // Initialize dp     dp = new int[a.Length, a.Length, a.Length];       // Initialize the states to -1     for(int i = 0; i < a.Length; i++)         for(int j = 0; j < a.Length; j++)             for(int k = 0; k < a.Length; k++)                 dp[i, j, k] = -1;       // Get answer     int ans = findSubsequence(a, sequence, 0, -1, 0);       // Print answer     Console.WriteLine((ans < 0) ? 0 : ans); }   // Driver code public static void Main() {           // Given array     int[] arr = { 5, 3, 9, 3, 4, 7 };       // Give arr1     int[] arr1 = { 3, 4 };       // Function Call     printAnswer(arr, arr1); } }   // This code is contributed by akhilsaini

Output:

3

Time Complexity: O(N3)
Auxiliary Space: O(N3)

My Personal Notes arrow_drop_up
Recommended Articles
Page :