Skip to content
Related Articles

Related Articles

Improve Article

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

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
Output: 
3

 

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

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.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :