📌  相关文章
📜  不包含给定序列作为子数组的最长递增子序列的长度

📅  最后修改于: 2021-04-22 08:41:53             🧑  作者: Mango

给定两个分别具有长度NM的数组arr []arr1 [] ,任务是找到数组arr []最长的递增子序列,以使其不包含数组arr1 []作为子数组。

例子:

天真的方法:最简单的方法是生成给定数组的所有可能的子序列,并打印其中最长的子序列的长度,其中不包含arr1 []作为子数组。

时间复杂度: O(M * 2 N ),其中N和M是给定数组的长度。
辅助空间: O(M + N)

高效方法:想法是使用通过KMP算法和动态编程生成的lps []数组来找到最长的非递减子序列,而没有任何等于sequence []的子数组。请按照以下步骤解决问题:

  1. 初始化数组dp [N] [N] [N] ,其中dp [i] [j] [K]存储不递减子序列的最大长度,直到索引i ,其中j是数组中先前选择的元素的索引arr []K表示当前找到的序列包含子数组sequence [0,K]
  2. 另外,使用KMP算法生成一个数组来存储最长前缀后缀的长度。
  3. 可以通过记住以下dp转换来找到最大长度:

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
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


输出:
3

时间复杂度: O(N 3 )
辅助空间: O(N 3 )