Open In App

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

Improve
Improve
Like Article
Like
Save
Share
Report

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


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>


Output: 

3

 

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

Related Topic: Subarrays, Subsequences, and Subsets in Array



Last Updated : 11 Jul, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads