Related Articles

Related Articles

Length of the longest increasing subsequence which does not contain a given sequence as Subarray
  • Last Updated : 06 Nov, 2020

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:

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

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

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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

chevron_right


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.




My Personal Notes arrow_drop_up
Recommended Articles
Page :