📜  打印最长双调子序列

📅  最后修改于: 2021-09-22 09:55:42             🧑  作者: Mango

最长双调子序列问题是找到给定序列的最长子序列,使其先增加然后减少。按递增顺序排序的序列被认为是双音,递减部分为空。类似地,降序序列被认为是双音的,递增部分为空。

例子:

Input:  [1, 11, 2, 10, 4, 5, 2, 1]
Output: [1, 2, 10, 4, 2, 1] OR [1, 11, 10, 5, 2, 1] 
    OR [1, 2, 4, 5, 2, 1]

Input:  [12, 11, 40, 5, 3, 1]
Output: [12, 11, 5, 3, 1] OR [12, 40, 5, 3, 1]

Input:  [80, 60, 30, 40, 20, 10]
Output: [80, 60, 30, 20, 10] OR [80, 60, 40, 20, 10]

在上一篇文章中,我们讨论了最长双调子序列问题。但是,该帖子仅涉及与查找递增子序列的最大和相关的代码,而不涉及子序列的构造。在这篇文章中,我们将讨论如何构建最长双调子序列本身。

令 arr[0..n-1] 为输入数组。我们定义向量 LIS 使得 LIS[i] 本身是一个向量,它存储以 arr[i] 结尾的 arr[0..i] 的最长递增子序列。因此,对于索引 i,LIS[i] 可以递归地写为 –

LIS[0] = {arr[O]}
LIS[i] = {Max(LIS[j])} + arr[i] where j < i and arr[j] < arr[i] 
       = arr[i], if there is no such j

我们还定义了一个向量 LDS,使得 LDS[i] 本身就是一个向量,它存储了以 arr[i] 开头的 arr[i..n] 的最长递减子序列。因此,对于索引 i,LDS[i] 可以递归地写为 –

LDS[n] = {arr[n]}
LDS[i] = arr[i] + {Max(LDS[j])} where j > i and arr[j] < arr[i] 
       = arr[i], if there is no such j

例如,对于数组 [1 11 2 10 4 5 2 1],

LIS[0]: 1
LIS[1]: 1 11
LIS[2]: 1 2
LIS[3]: 1 2 10
LIS[4]: 1 2 4
LIS[5]: 1 2 4 5
LIS[6]: 1 2
LIS[7]: 1
LDS[0]: 1
LDS[1]: 11 10 5 2 1
LDS[2]: 2 1
LDS[3]: 10 5 2 1
LDS[4]: 4 2 1
LDS[5]: 5 2 1
LDS[6]: 2 1
LDS[7]: 1

因此,最长双调子序列可以是

LIS[1] + LDS[1] = [1 11 10 5 2 1]        OR
LIS[3] + LDS[3] = [1 2 10 5 2 1]        OR
LIS[5] + LDS[5] = [1 2 4 5 2 1]

以下是上述想法的实现——

C++
/* Dynamic Programming solution to print Longest
   Bitonic Subsequence */
#include 
using namespace std;
  
// Utility function to print Longest Bitonic
// Subsequence
void print(vector& arr, int size)
{
    for(int i = 0; i < size; i++)
        cout << arr[i] << " ";
}
  
// Function to construct and print Longest
// Bitonic Subsequence
void printLBS(int arr[], int n)
{
    // LIS[i] stores the length of the longest
    // increasing subsequence ending with arr[i]
    vector> LIS(n);
  
    // initialize LIS[0] to arr[0]
    LIS[0].push_back(arr[0]);
  
    // Compute LIS values from left to right
    for (int i = 1; i < n; i++)
    {
        // for every j less than i
        for (int j = 0; j < i; j++)
        {
            if ((arr[j] < arr[i]) &&
                (LIS[j].size() > LIS[i].size()))
                LIS[i] = LIS[j];
        }
        LIS[i].push_back(arr[i]);
    }
  
    /* LIS[i] now stores Maximum Increasing
       Subsequence of arr[0..i] that ends with
       arr[i] */
  
    // LDS[i] stores the length of the longest
    // decreasing subsequence starting with arr[i]
    vector> LDS(n);
  
    // initialize LDS[n-1] to arr[n-1]
    LDS[n - 1].push_back(arr[n - 1]);
  
    // Compute LDS values from right to left
    for (int i = n - 2; i >= 0; i--)
    {
        // for every j greater than i
        for (int j = n - 1; j > i; j--)
        {
            if ((arr[j] < arr[i]) &&
                (LDS[j].size() > LDS[i].size()))
                LDS[i] = LDS[j];
        }
        LDS[i].push_back(arr[i]);
    }
  
    // reverse as vector as we're inserting at end
    for (int i = 0; i < n; i++)
        reverse(LDS[i].begin(), LDS[i].end());
  
    /* LDS[i] now stores Maximum Decreasing Subsequence
       of arr[i..n] that starts with arr[i] */
  
    int max = 0;
    int maxIndex = -1;
  
    for (int i = 0; i < n; i++)
    {
        // Find maximum value of size of LIS[i] + size
        // of LDS[i] - 1
        if (LIS[i].size() + LDS[i].size() - 1 > max)
        {
            max = LIS[i].size() + LDS[i].size() - 1;
            maxIndex = i;
        }
    }
  
    // print all but last element of LIS[maxIndex] vector
    print(LIS[maxIndex], LIS[maxIndex].size() - 1);
  
    // print all elements of LDS[maxIndex] vector
    print(LDS[maxIndex], LDS[maxIndex].size());
}
  
// Driver program
int main()
{
    int arr[] = { 1, 11, 2, 10, 4, 5, 2, 1 };
    int n = sizeof(arr) / sizeof(arr[0]);
  
    printLBS(arr, n);
    return 0;
}


Java
/* Dynamic Programming solution to print Longest 
Bitonic Subsequence */
import java.util.*;
  
class GFG 
{
  
    // Utility function to print Longest Bitonic
    // Subsequence
    static void print(Vector arr, int size) 
    {
        for (int i = 0; i < size; i++)
            System.out.print(arr.elementAt(i) + " ");
    }
  
    // Function to construct and print Longest
    // Bitonic Subsequence
    static void printLBS(int[] arr, int n) 
    {
  
        // LIS[i] stores the length of the longest
        // increasing subsequence ending with arr[i]
        @SuppressWarnings("unchecked")
        Vector[] LIS = new Vector[n];
  
        for (int i = 0; i < n; i++)
            LIS[i] = new Vector<>();
  
        // initialize LIS[0] to arr[0]
        LIS[0].add(arr[0]);
  
        // Compute LIS values from left to right
        for (int i = 1; i < n; i++) 
        {
  
            // for every j less than i
            for (int j = 0; j < i; j++) 
            {
  
                if ((arr[i] > arr[j]) && 
                     LIS[j].size() > LIS[i].size()) 
                {
                    for (int k : LIS[j])
                        if (!LIS[i].contains(k))
                            LIS[i].add(k);
                }
            }
            LIS[i].add(arr[i]);
        }
  
        /*
        * LIS[i] now stores Maximum Increasing Subsequence 
        * of arr[0..i] that ends with arr[i]
        */
  
        // LDS[i] stores the length of the longest
        // decreasing subsequence starting with arr[i]
        @SuppressWarnings("unchecked")
        Vector[] LDS = new Vector[n];
  
        for (int i = 0; i < n; i++)
            LDS[i] = new Vector<>();
  
        // initialize LDS[n-1] to arr[n-1]
        LDS[n - 1].add(arr[n - 1]);
  
        // Compute LDS values from right to left
        for (int i = n - 2; i >= 0; i--) 
        {
  
            // for every j greater than i
            for (int j = n - 1; j > i; j--) 
            {
                if (arr[j] < arr[i] && 
                    LDS[j].size() > LDS[i].size())
                    for (int k : LDS[j])
                        if (!LDS[i].contains(k))
                            LDS[i].add(k);
            }
            LDS[i].add(arr[i]);
        }
  
        // reverse as vector as we're inserting at end
        for (int i = 0; i < n; i++)
            Collections.reverse(LDS[i]);
  
        /*
        * LDS[i] now stores Maximum Decreasing Subsequence 
        * of arr[i..n] that starts with arr[i]
        */
        int max = 0;
        int maxIndex = -1;
        for (int i = 0; i < n; i++)
        {
  
            // Find maximum value of size of 
            // LIS[i] + size of LDS[i] - 1
            if (LIS[i].size() + LDS[i].size() - 1 > max)
            {
                max = LIS[i].size() + LDS[i].size() - 1;
                maxIndex = i;
            }
        }
  
        // print all but last element of LIS[maxIndex] vector
        print(LIS[maxIndex], LIS[maxIndex].size() - 1);
  
        // print all elements of LDS[maxIndex] vector
        print(LDS[maxIndex], LDS[maxIndex].size());
    }
  
    // Driver Code
    public static void main(String[] args) 
    {
        int[] arr = { 1, 11, 2, 10, 4, 5, 2, 1 };
        int n = arr.length;
  
        printLBS(arr, n);
    }
}
  
// This code is contributed by
// sanjeev2552


Python3
# Dynamic Programming solution to print Longest
# Bitonic Subsequence
  
  
def _print(arr: list, size: int):
    for i in range(size):
        print(arr[i], end=" ")
  
  
# Function to construct and print Longest
# Bitonic Subsequence
def printLBS(arr: list, n: int):
  
    # LIS[i] stores the length of the longest
    # increasing subsequence ending with arr[i]
    LIS = [0] * n
    for i in range(n):
        LIS[i] = []
  
    # initialize LIS[0] to arr[0]
    LIS[0].append(arr[0])
  
    # Compute LIS values from left to right
    for i in range(1, n):
  
        # for every j less than i
        for j in range(i):
  
            if ((arr[j] < arr[i]) and (len(LIS[j]) > len(LIS[i]))):
                LIS[i] = LIS[j].copy()
  
        LIS[i].append(arr[i])
  
    # LIS[i] now stores Maximum Increasing
    # Subsequence of arr[0..i] that ends with
    # arr[i]
  
    # LDS[i] stores the length of the longest
    # decreasing subsequence starting with arr[i]
    LDS = [0] * n
    for i in range(n):
        LDS[i] = []
  
    # initialize LDS[n-1] to arr[n-1]
    LDS[n - 1].append(arr[n - 1])
  
    # Compute LDS values from right to left
    for i in range(n - 2, -1, -1):
  
        # for every j greater than i
        for j in range(n - 1, i, -1):
  
            if ((arr[j] < arr[i]) and (len(LDS[j]) > len(LDS[i]))):
                LDS[i] = LDS[j].copy()
  
        LDS[i].append(arr[i])
  
    # reverse as vector as we're inserting at end
    for i in range(n):
        LDS[i] = list(reversed(LDS[i]))
  
    # LDS[i] now stores Maximum Decreasing Subsequence
    # of arr[i..n] that starts with arr[i]
  
    max = 0
    maxIndex = -1
  
    for i in range(n):
  
        # Find maximum value of size of LIS[i] + size
        # of LDS[i] - 1
        if (len(LIS[i]) + len(LDS[i]) - 1 > max):
  
            max = len(LIS[i]) + len(LDS[i]) - 1
            maxIndex = i
  
    # print all but last element of LIS[maxIndex] vector
    _print(LIS[maxIndex], len(LIS[maxIndex]) - 1)
  
    # print all elements of LDS[maxIndex] vector
    _print(LDS[maxIndex], len(LDS[maxIndex]))
  
  
# Driver Code
if __name__ == "__main__":
  
    arr = [1, 11, 2, 10, 4, 5, 2, 1]
    n = len(arr)
  
    printLBS(arr, n)
  
# This code is contributed by
# sanjeev2552


C#
/* Dynamic Programming solution to print longest 
Bitonic Subsequence */
using System;
using System.Linq;
using System.Collections.Generic;
  
class GFG 
{
  
    // Utility function to print longest Bitonic
    // Subsequence
    static void print(List arr, int size) 
    {
        for (int i = 0; i < size; i++)
            Console.Write(arr[i] + " ");
    }
  
    // Function to construct and print longest
    // Bitonic Subsequence
    static void printLBS(int[] arr, int n) 
    {
  
        // LIS[i] stores the length of the longest
        // increasing subsequence ending with arr[i]
        List[] LIS = new List[n];
  
        for (int i = 0; i < n; i++)
            LIS[i] = new List();
  
        // initialize LIS[0] to arr[0]
        LIS[0].Add(arr[0]);
  
        // Compute LIS values from left to right
        for (int i = 1; i < n; i++) 
        {
  
            // for every j less than i
            for (int j = 0; j < i; j++) 
            {
  
                if ((arr[i] > arr[j]) && 
                    LIS[j].Count > LIS[i].Count) 
                {
                    foreach (int k in LIS[j])
                        if (!LIS[i].Contains(k))
                            LIS[i].Add(k);
                }
            }
            LIS[i].Add(arr[i]);
        }
  
        /*
        * LIS[i] now stores Maximum Increasing Subsequence 
        * of arr[0..i] that ends with arr[i]
        */
  
        // LDS[i] stores the length of the longest
        // decreasing subsequence starting with arr[i]
        List[] LDS = new List[n];
  
        for (int i = 0; i < n; i++)
            LDS[i] = new List();
  
        // initialize LDS[n-1] to arr[n-1]
        LDS[n - 1].Add(arr[n - 1]);
  
        // Compute LDS values from right to left
        for (int i = n - 2; i >= 0; i--) 
        {
  
            // for every j greater than i
            for (int j = n - 1; j > i; j--) 
            {
                if (arr[j] < arr[i] && 
                    LDS[j].Count > LDS[i].Count)
                    foreach (int k in LDS[j])
                        if (!LDS[i].Contains(k))
                            LDS[i].Add(k);
            }
            LDS[i].Add(arr[i]);
        }
  
        // reverse as vector as we're inserting at end
        for (int i = 0; i < n; i++)
            LDS[i].Reverse();
  
        /*
        * LDS[i] now stores Maximum Decreasing Subsequence 
        * of arr[i..n] that starts with arr[i]
        */
        int max = 0;     
        int maxIndex = -1;
        for (int i = 0; i < n; i++)
        {
  
            // Find maximum value of size of 
            // LIS[i] + size of LDS[i] - 1
            if (LIS[i].Count + LDS[i].Count - 1 > max)
            {
                max = LIS[i].Count + LDS[i].Count - 1;
                maxIndex = i;
            }
        }
  
        // print all but last element of LIS[maxIndex] vector
        print(LIS[maxIndex], LIS[maxIndex].Count - 1);
  
        // print all elements of LDS[maxIndex] vector
        print(LDS[maxIndex], LDS[maxIndex].Count);
    }
  
    // Driver Code
    public static void Main(String[] args) 
    {
        int[] arr = { 1, 11, 2, 10, 4, 5, 2, 1 };
        int n = arr.Length;
  
        printLBS(arr, n);
    }
}
  
// This code is contributed by PrinciRaj1992


输出:

1 11 10 5 2 1

上述动态规划解决方案的时间复杂度为 O(n 2 )。
程序使用的辅助空间为O(n 2 )。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程