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++ 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 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);
}
} |
# 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# 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 |
<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