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:
- 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].
- Also, generate an array to store the length of the longest prefix suffix using KMP Algorithm.
- 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 <bits/stdc++.h> using namespace std; // Initialize dp and KMP array int dp[6][6][6]; int KMPArray[2]; // 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[0] is a always 0 KMPArray[0] = 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[0] is a always 0 KMPArray[ 0 ] = 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); } } |
Python3
# Python program for the above approach # Initialize dp and KMP array from pickle import GLOBAL import sys dp = [[[ - 1 for i in range ( 6 )] for j in range ( 6 )] for k in range ( 6 )] KMPArray = [ 0 for i in range ( 2 )] # Length of the given sequence[] m = 0 # Function to find the max-length # subsequence that does not have # subarray sequence[] def findSubsequence(a, sequence, i,prev, k, al, sl): global KMPArray global dp # Stores the subsequence # explored so far if (k = = m): return - sys.maxsize - 1 # Base Case if (i = = al): return 0 # Using memoization to # avoid re-computation if (prev ! = - 1 and dp[i][prev][k] ! = - 1 ): return dp[i][prev][k] include = 0 if (prev = = - 1 or a[i] > = a[prev]): k2 = k # Using KMP array to find # corresponding index in arr1[] while (k2 > 0 and 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 + = 1 # Possible answer for # current state include = 1 + findSubsequence( a, sequence, i + 1 , i, k2, al, sl) # Maximum answer for # current state 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 def fillKMPArray(pattern): global m global KMPArray # Previous longest prefix suffix j = 0 i = 1 # KMPArray[0] is a always 0 KMPArray[ 0 ] = 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 + = 1 # Update the KMP array KMPArray[i] = j i + = 1 # Otherwise else : # Update the KMP array if (j ! = 0 ): j = KMPArray[j - 1 ] else : KMPArray[i] = j i + = 1 # Function to print the maximum # possible length def printAnswer(a, sequence, al, sl): global m # Length of the given sequence m = sl # Generate KMP array fillKMPArray(sequence) # Get answer ans = findSubsequence(a, sequence, 0 , - 1 , 0 , al, sl) # Print answer if (ans < 0 ): print ( 0 ) else : print (ans) # Driver code # Given array arr = [ 5 , 3 , 9 , 3 , 4 , 7 ] # Give arr1 arr1 = [ 3 , 4 ] # Function Call printAnswer(arr, arr1, 6 , 2 ) # This code is contributed by shinjanpatra |
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[0] is a always 0 KMPArray[0] = 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 |
Javascript
<script> // JavaScript program to implement above approach // Initialize dp and KMP array let dp = new Array(6).fill(-1).map(()=> new Array(6).fill(-1).map(()=> new Array(6).fill(-1))); let KMPArray = new Array(2); // Length of the given sequence let m; // Function to find the max-length // subsequence that does not have // subarray sequence[] function findSubsequence(a, sequence, i,prev, k, al, sl) { // Stores the subsequence // explored so far if (k == m) return Number.MIN_VALUE; // 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]; } let include = 0; if (prev == -1 || a[i] >= a[prev]) { let 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 let ans = Math.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 function fillKMPArray(pattern) { // Previous longest prefix suffix let j = 0; let i = 1; // KMPArray[0] is a always 0 KMPArray[0] = 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 function printAnswer(a, sequence, al, sl) { // Length of the given sequence m = sl; // Generate KMP array fillKMPArray(sequence); // Get answer let ans = findSubsequence(a, sequence, 0, -1, 0, al, sl); // Print answer console.log((ans < 0) ? 0 : ans); } // Driver code // Given array let arr = [ 5, 3, 9, 3, 4, 7 ]; // Give arr1 let arr1 = [ 3, 4 ]; // Function Call printAnswer(arr, arr1, 6, 2); // This code is contributed by shinjanpatra </script> |
3
Time Complexity: O(N3)
Auxiliary Space: O(N3)
Related Topic: Subarrays, Subsequences, and Subsets in Array
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!