📜  最长递增子序列大小 (N log N)

📅  最后修改于: 2021-09-17 06:48:15             🧑  作者: Mango

给定一组随机数。在数组中查找最长递增子序列(LIS)。我知道你们中的许多人可能已经阅读过递归和动态编程 (DP) 解决方案。论坛帖子中对 O(N log N) 算法的请求很少。

暂时忘记递归和DP解决方案。让我们取小样本并将解决方案扩展到大实例。尽管第一次看起来可能很复杂,但一旦我们理解了逻辑,编码就很简单了。
考虑输入数组 A = {2, 5, 3}。我将在解释期间扩展数组。
通过观察我们知道 LIS 是 {2, 3} 或 {2, 5}。请注意,我只考虑严格递增序列
让我们再添加两个元素,比如 7, 11 到数组中。这些元素将扩展现有序列。现在输入数组 {2, 5, 3, 7, 11} 的递增序列是 {2, 3, 7, 11} 和 {2, 5, 7, 11}。
此外,我们再添加一个元素,比如 8 到数组中,即输入数组变为 {2, 5, 3, 7, 11, 8}。请注意,最新的元素 8 大于任何活动序列的最小元素(稍后将讨论有关活动序列的内容)。我们如何用 8 扩展现有序列?首先,8可以成为LIS的一部分吗?如果是,如何?如果我们要添加 8,它应该在 7 之后(通过替换 11)。
由于该方法是离线的(我们所说的离线什么意思?) ,我们不确定添加 8 是否会扩展系列。假设输入数组中有 9 个,比如 {2, 5, 3, 7, 11, 8, 7, 9 …}。我们可以将 11 替换为 8,因为存在可以扩展新系列 {2, 3, 7, 8} 或 {2, 5, 7, 8} 的潜在最佳候选 (9)。
我们的观察是,假设最大序列的结束元素是 E。如果存在元素 A[j] (j > i) 使得 E < A,我们可以将当前元素 A[i] 添加(替换)到现有序列[i] < A[j] 或 (E > A[i] < A[j] – 用于替换)。在上面的例子中,E = 11,A[i] = 8 和 A[j] = 9。
对于我们的原始数组 {2, 5, 3},请注意,当我们将 3 添加到递增序列 {2, 5} 时,我们面临相同的情况。我刚刚创建了两个递增序列来简化解释。代替两个序列,3 可以替换序列{2, 5} 中的 5。
我知道这会令人困惑,我很快就会清除它!
问题是,什么时候添加或替换现有序列中的元素是安全的?
让我们考虑另一个样本 A = {2, 5, 3}。假设下一个元素是 1。它如何扩展当前序列 {2, 3} 或 {2, 5}。显然,它也不能扩展。然而,新的最小元素有可能成为 LIS 的开始。为了清楚起见,考虑数组是 {2, 5, 3, 1, 2, 3, 4, 5, 6}。将 1 作为新序列将创建最大的新序列。
观察结果是,当我们遇到数组中新的最小元素时,它可能是开始新序列的潜在候选者。
根据观察,我们需要维护递增序列的列表。
一般来说,我们有一组不同长度的活动列表。我们正在向这些列表中添加一个元素 A[i]。我们按长度递减的顺序扫描列表(用于结束元素)。我们将核实所有列表的末尾元素查找其结束元素比[I](本底值)小的列表。
我们的策略由以下条件决定,

1. If A[i] is smallest among all end 
   candidates of active lists, we will start 
   new active list of length 1.
2. If A[i] is largest among all end candidates of 
  active lists, we will clone the largest active 
  list, and extend it by A[i].
3. If A[i] is in between, we will find a list with 
  largest end element that is smaller than A[i]. 
  Clone and extend this list by A[i]. We will discard all
  other lists of same length as that of this modified list.

请注意,在我们构建活动列表期间的任何情况下,都会保持以下条件。
“较小列表的结尾元素小于较大列表的结尾元素”
举个例子就清楚了,让我们以维基{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}为例。

A[0] = 0. Case 1. There are no active lists, create one.
0.
-----------------------------------------------------------------------------
A[1] = 8. Case 2. Clone and extend.
0.
0, 8.
-----------------------------------------------------------------------------
A[2] = 4. Case 3. Clone, extend and discard.
0.
0, 4.
0, 8. Discarded
-----------------------------------------------------------------------------
A[3] = 12. Case 2. Clone and extend.
0.
0, 4.
0, 4, 12.
-----------------------------------------------------------------------------
A[4] = 2. Case 3. Clone, extend and discard.
0.
0, 2.
0, 4. Discarded.
0, 4, 12.
-----------------------------------------------------------------------------
A[5] = 10. Case 3. Clone, extend and discard.
0.
0, 2.
0, 2, 10.
0, 4, 12. Discarded.
-----------------------------------------------------------------------------
A[6] = 6. Case 3. Clone, extend and discard.
0.
0, 2.
0, 2, 6.
0, 2, 10. Discarded.
-----------------------------------------------------------------------------
A[7] = 14. Case 2. Clone and extend.
0.
0, 2.
0, 2, 6.
0, 2, 6, 14.
-----------------------------------------------------------------------------
A[8] = 1. Case 3. Clone, extend and discard.
0.
0, 1.
0, 2. Discarded.
0, 2, 6.
0, 2, 6, 14.
-----------------------------------------------------------------------------
A[9] = 9. Case 3. Clone, extend and discard.
0.
0, 1.
0, 2, 6.
0, 2, 6, 9.
0, 2, 6, 14. Discarded.
-----------------------------------------------------------------------------
A[10] = 5. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 5.
0, 2, 6. Discarded.
0, 2, 6, 9.
-----------------------------------------------------------------------------
A[11] = 13. Case 2. Clone and extend.
0.
0, 1.
0, 1, 5.
0, 2, 6, 9.
0, 2, 6, 9, 13.
-----------------------------------------------------------------------------
A[12] = 3. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 3.
0, 1, 5. Discarded.
0, 2, 6, 9.
0, 2, 6, 9, 13.
-----------------------------------------------------------------------------
A[13] = 11. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 3.
0, 2, 6, 9.
0, 2, 6, 9, 11.
0, 2, 6, 9, 13. Discarded.
-----------------------------------------------------------------------------
A[14] = 7. Case 3. Clone, extend and discard.
0.
0, 1.
0, 1, 3.
0, 1, 3, 7.
0, 2, 6, 9. Discarded.
0, 2, 6, 9, 11.
----------------------------------------------------------------------------
A[15] = 15. Case 2. Clone and extend.
0.
0, 1.
0, 1, 3.
0, 1, 3, 7.
0, 2, 6, 9, 11.
0, 2, 6, 9, 11, 15. <-- LIS List
----------------------------------------------------------------------------

需要理解上述策略才能设计算法。另外,确保我们保持了条件,“较小列表的结尾元素小于较大列表的结尾元素”。在进一步阅读之前,请尝试一些其他示例。了解结束元素发生了什么很重要。
算法:
查询最长的长度相当容易。请注意,我们仅处理结束元素。我们不需要维护所有列表。我们可以将结束元素存储在数组中。丢弃操作可以用替换来模拟,扩展列表类似于向数组添加更多元素。
我们将使用一个辅助数组来保留结束元素。该数组的最大长度是输入的长度。在最坏的情况下,数组分为 N 个大小为 1 的列表(请注意,它不会导致最坏情况的复杂性)。为了丢弃一个元素,我们将在辅助数组中追踪 A[i] 的 ceil 值(再次观察你粗略工作中的结束元素),并将 ceil 值替换为 A[i]。我们通过向辅助数组添加元素来扩展列表。我们还维护一个计数器来跟踪辅助数组的长度。
奖励:你已经部分学习了耐心排序技术🙂
有一句谚语说:“告诉我,我会忘记的。给我看,我会记住的。让我参与,我就会明白。”所以,从一副纸牌中挑选一套西装。从洗好的花色中找出最长的递增子序列。你永远不会忘记这种方法。 🙂
更新 – 2016 年 7 月 17 日:读者的反应令人印象深刻,很少有网站引用该帖子,因为我的努力帮助他人而感到高兴。看起来读者在发表评论之前没有做任何功课。要求在阅读文章后运行一些示例,并请在纸上进行工作(不要使用编辑器/编译器)。请求是帮助自己。自称“知道”不同于真正的理解(没有不尊重)。下面给出的是我的个人经验。
最初的内容准备对我来说大约花了 6 个小时。但是,这是一个很好的教训。我在一个小时内完成了初始代码。当我开始写内容向读者解释时,我意识到我没有理解这些案例。拿了我的笔记本(我有保持装订笔记本的习惯,以记录我粗略的工作),几个小时后,我填写了近 15 页的粗略工作。无论您在灰色示例中看到的内容来自这些页面。解决方案的所有思考过程都由“Udi Manber 的算法简介”一书中的注释引发,我强烈建议练习这本书。
我怀疑,许多读者可能无法理解 CeilIndex(二进制搜索)背后的逻辑。我把它作为练习留给读者来理解它是如何工作的。在纸上运行几个例子。我意识到我已经在另一篇文章中介绍了该算法。
更新 – 2016 年 8 月 5 日
以下链接值得在您完成工作后参考。我通过我最近创建的Disqus个人资料知道了这个链接。该链接解释了 Wiki 中提到的方法。
http://stackoverflow.com/questions/2631726/how-to-determine-the-longest-increasing-subsequence-using-dynamic-programming
下面给出的是查找 LIS 长度的代码(更新为 C++11 代码,没有 C 样式数组),

C++
#include 
#include 
 
// Binary search (note boundaries in the caller)
int CeilIndex(std::vector& v, int l, int r, int key)
{
    while (r - l > 1) {
        int m = l + (r - l) / 2;
        if (v[m] >= key)
            r = m;
        else
            l = m;
    }
 
    return r;
}
 
int LongestIncreasingSubsequenceLength(std::vector& v)
{
    if (v.size() == 0)
        return 0;
 
    std::vector tail(v.size(), 0);
    int length = 1; // always points empty slot in tail
 
    tail[0] = v[0];
    for (size_t i = 1; i < v.size(); i++) {
 
        // new smallest value
        if (v[i] < tail[0])
            tail[0] = v[i];
 
        // v[i] extends largest subsequence
        else if (v[i] > tail[length - 1])
            tail[length++] = v[i];
 
        // v[i] will become end candidate of an existing
        // subsequence or Throw away larger elements in all
        // LIS, to make room for upcoming greater elements
        // than v[i] (and also, v[i] would have already
        // appeared in one of LIS, identify the location
        // and replace it)
        else
            tail[CeilIndex(tail, -1, length - 1, v[i])] = v[i];
    }
 
    return length;
}
 
int main()
{
    std::vector v{ 2, 5, 3, 7, 11, 8, 10, 13, 6 };
    std::cout << "Length of Longest Increasing Subsequence is "
              << LongestIncreasingSubsequenceLength(v) << '\n';
    return 0;
}


Java
// Java program to find length of longest increasing subsequence
// in O(n Log n) time
import java.io.*;
import java.util.*;
import java.lang.Math;
 
class LIS {
    // Binary search (note boundaries in the caller)
    // A[] is ceilIndex in the caller
    static int CeilIndex(int A[], int l, int r, int key)
    {
        while (r - l > 1) {
            int m = l + (r - l) / 2;
            if (A[m] >= key)
                r = m;
            else
                l = m;
        }
 
        return r;
    }
 
    static int LongestIncreasingSubsequenceLength(int A[], int size)
    {
        // Add boundary case, when array size is one
 
        int[] tailTable = new int[size];
        int len; // always points empty slot
 
        tailTable[0] = A[0];
        len = 1;
        for (int i = 1; i < size; i++) {
            if (A[i] < tailTable[0])
                // new smallest value
                tailTable[0] = A[i];
 
            else if (A[i] > tailTable[len - 1])
                // A[i] wants to extend largest subsequence
                tailTable[len++] = A[i];
 
            else
                // A[i] wants to be current end candidate of an existing
                // subsequence. It will replace ceil value in tailTable
                tailTable[CeilIndex(tailTable, -1, len - 1, A[i])] = A[i];
        }
 
        return len;
    }
 
    // Driver program to test above function
    public static void main(String[] args)
    {
        int A[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
        int n = A.length;
        System.out.println("Length of Longest Increasing Subsequence is " + LongestIncreasingSubsequenceLength(A, n));
    }
}
/* This code is contributed by Devesh Agrawal*/


Python3
# Python program to find
# length of longest
# increasing subsequence
# in O(n Log n) time
 
# Binary search (note
# boundaries in the caller)
# A[] is ceilIndex
# in the caller
def CeilIndex(A, l, r, key):
 
    while (r - l > 1):
     
        m = l + (r - l)//2
        if (A[m] >= key):
            r = m
        else:
            l = m
    return r
  
def LongestIncreasingSubsequenceLength(A, size):
 
    # Add boundary case,
    # when array size is one
  
    tailTable = [0 for i in range(size + 1)]
    len = 0 # always points empty slot
  
    tailTable[0] = A[0]
    len = 1
    for i in range(1, size):
     
        if (A[i] < tailTable[0]):
 
            # new smallest value
            tailTable[0] = A[i]
  
        elif (A[i] > tailTable[len-1]):
 
            # A[i] wants to extend
            # largest subsequence
            tailTable[len] = A[i]
            len+= 1
  
        else:
            # A[i] wants to be current
            # end candidate of an existing
            # subsequence. It will replace
            # ceil value in tailTable
            tailTable[CeilIndex(tailTable, -1, len-1, A[i])] = A[i]
         
  
    return len
 
  
# Driver program to
# test above function
 
A = [ 2, 5, 3, 7, 11, 8, 10, 13, 6 ]
n = len(A)
 
print("Length of Longest Increasing Subsequence is ",
       LongestIncreasingSubsequenceLength(A, n))
 
# This code is contributed
# by Anant Agarwal.


C#
// C# program to find length of longest
// increasing subsequence in O(n Log n)
// time
using System;
 
class GFG {
 
    // Binary search (note boundaries
    // in the caller) A[] is ceilIndex
    // in the caller
    static int CeilIndex(int[] A, int l,
                         int r, int key)
    {
        while (r - l > 1) {
            int m = l + (r - l) / 2;
 
            if (A[m] >= key)
                r = m;
            else
                l = m;
        }
 
        return r;
    }
 
    static int LongestIncreasingSubsequenceLength(
        int[] A, int size)
    {
 
        // Add boundary case, when array size
        // is one
 
        int[] tailTable = new int[size];
        int len; // always points empty slot
 
        tailTable[0] = A[0];
        len = 1;
        for (int i = 1; i < size; i++) {
            if (A[i] < tailTable[0])
                // new smallest value
                tailTable[0] = A[i];
 
            else if (A[i] > tailTable[len - 1])
 
                // A[i] wants to extend largest
                // subsequence
                tailTable[len++] = A[i];
 
            else
 
                // A[i] wants to be current end
                // candidate of an existing
                // subsequence. It will replace
                // ceil value in tailTable
                tailTable[CeilIndex(tailTable, -1,
                                    len - 1, A[i])]
                    = A[i];
        }
 
        return len;
    }
 
    // Driver program to test above function
    public static void Main()
    {
        int[] A = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
        int n = A.Length;
        Console.Write("Length of Longest "
                      + "Increasing Subsequence is " + LongestIncreasingSubsequenceLength(A, n));
    }
}
 
// This code is contributed by nitin mittal.


PHP
 1)
    {
        $m = (int)($l + ($r - $l)/2);
        if ($A[$m] >= $key)
            $r = $m;
        else
            $l = $m;
    }
    return $r;
}
 
function LongestIncreasingSubsequenceLength($A, $size)
{
    // Add boundary case,
    // when array size is one
 
    $tailTable = array_fill(0, ($size + 1), 0);
    $len = 0; // always points empty slot
 
    $tailTable[0] = $A[0];
    $len = 1;
    for($i = 1; $i < $size; $i++)
    {
     
        if ($A[$i] < $tailTable[0])
            // new smallest value
            $tailTable[0] = $A[$i];
 
        else if ($A[$i] > $tailTable[$len-1])
        {
            // A[i] wants to extend
            // largest subsequence
            $tailTable[$len] = $A[$i];
            $len++;
        }
        else
            // A[i] wants to be current
            // end candidate of an existing
            // subsequence. It will replace
            // ceil value in tailTable
            $tailTable[CeilIndex($tailTable, -1, $len-1, $A[$i])] = $A[$i];
         
    }
    return $len;
}
 
// Driver program to
// test above function
$A = array( 2, 5, 3, 7, 11, 8, 10, 13, 6 );
$n = count($A);
 
print("Length of Longest Increasing Subsequence is ".
        LongestIncreasingSubsequenceLength($A, $n));
 
// This code is contributed by chandan_jnu
?>


CPP
#include 
using namespace std;
 
int LongestIncreasingSubsequenceLength(std::vector& v)
{
    if (v.size() == 0) // boundry case
        return 0;
 
    std::vector tail(v.size(), 0);
    int length = 1; // always points empty slot in tail
 
    tail[0] = v[0];
 
    for (int i = 1; i < v.size(); i++) {
 
        // Do binary search for the element in
        // the range from begin to begin + length
        auto b = tail.begin(), e = tail.begin() + length;
        auto it = lower_bound(b, e, v[i]);
 
        // If not present change the tail element to v[i]
        if (it == tail.begin() + length)
            tail[length++] = v[i];
        else
            *it = v[i];
    }
 
    return length;
}
 
int main()
{
    std::vector v{ 2, 5, 3, 7, 11, 8, 10, 13, 6 };
    std::cout
        << "Length of Longest Increasing Subsequence is "
        << LongestIncreasingSubsequenceLength(v);
    return 0;
}


Python3
from bisect import bisect_left
 
 
def LongestIncreasingSubsequenceLength(v):
    if len(v) == 0:  # boundry case
        return 0
 
    tail = [0 for i in range(len(v) + 1)]
    length = 1  # always points empty slot in tail
 
    tail[0] = v[0]
 
    for i in range(1, len(v)):
        if v[i] > tail[length-1]:
            # v[i] extends the largest subsequence
            tail[length] = v[i]
            length += 1
 
        else:
            # v[i] will extend a subsequence and discard older subsequence
 
            # find the largest value just smaller than v[i] in tail
 
            # to find that value do binary search for the v[i] in
            # the range from begin to 0 + length
 
            # bisect function either returns index where element is found
            # or the appropriate index at which element should be placed
 
            # finally replace the existing subsequene with new end value
            tail[bisect_left(tail, v[i], 0, length-1)] = v[i]
 
    return length
 
 
# Driver program to test above function
v = [2, 5, 3, 7, 11, 8, 10, 13, 6]
print("Length of Longest Increasing Subsequence is ",
      LongestIncreasingSubsequenceLength(v))
 
# This code is contributed by Serjeel Ranjan


Java
import java.io.*;
import java.lang.Math;
import java.util.*;
 
class LIS {
    static int LongestIncreasingSubsequenceLength(int v[])
    {
        if (v.length == 0) // boundry case
            return 0;
 
        int[] tail = new int[v.length];
        int length = 1; // always points empty slot in tail
        tail[0] = v[0];
 
        for (int i = 1; i < v.length; i++) {
 
            if (v[i] > tail[length - 1]) {
                // v[i] extends the largest subsequence
                tail[length++] = v[i];
            }
            else {
                // v[i] will extend a subsequence and
                // discard older subsequence
 
                // find the largest value just smaller than
                // v[i] in tail
 
                // to find that value do binary search for
                // the v[i] in the range from begin to 0 +
                // length
                int idx = Arrays.binarySearch(
                    tail, 0, length - 1, v[i]);
 
                // binarySearch in java returns negative
                // value if searched element is not found in
                // array
 
                // this negative value stores the
                // appropriate place where the element is
                // supposed to be stored
                if (idx < 0)
                    idx = -1 * idx - 1;
 
                // replacing the existing subsequene with
                // new end value
                tail[idx] = v[i];
            }
        }
        return length;
    }
 
    // Driver program to test above function
    public static void main(String[] args)
    {
        int v[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
        System.out.println(
            "Length of Longest Increasing Subsequence is "
            + LongestIncreasingSubsequenceLength(v));
    }
}
 
/* This code is contributed by Serjeel Ranjan */


输出:

Length of Longest Increasing Subsequence is 6

复杂:
循环运行 N 个元素。在最坏的情况下(最坏情况的输入是什么?),我们最终可能会使用二分搜索(log i )来查询许多 A[i] 的 ceil 值。
因此,T(n) < O( log N! ) = O(N log N)。分析确保上下界也是 O( N log N )。复杂度是 THETA (N log N)。
练习:
1. 设计一个算法来构造最长递增列表。此外,使用 DAG 为您的解决方案建模。
2. 设计一个算法来构造所有长度相等的递增列表。
3.以上算法是在线算法吗?
4. 设计一个算法来构造最长递减列表。
下面给出了使用其内置二进制搜索函数在各种语言中的替代实现:

CPP

#include 
using namespace std;
 
int LongestIncreasingSubsequenceLength(std::vector& v)
{
    if (v.size() == 0) // boundry case
        return 0;
 
    std::vector tail(v.size(), 0);
    int length = 1; // always points empty slot in tail
 
    tail[0] = v[0];
 
    for (int i = 1; i < v.size(); i++) {
 
        // Do binary search for the element in
        // the range from begin to begin + length
        auto b = tail.begin(), e = tail.begin() + length;
        auto it = lower_bound(b, e, v[i]);
 
        // If not present change the tail element to v[i]
        if (it == tail.begin() + length)
            tail[length++] = v[i];
        else
            *it = v[i];
    }
 
    return length;
}
 
int main()
{
    std::vector v{ 2, 5, 3, 7, 11, 8, 10, 13, 6 };
    std::cout
        << "Length of Longest Increasing Subsequence is "
        << LongestIncreasingSubsequenceLength(v);
    return 0;
}

蟒蛇3

from bisect import bisect_left
 
 
def LongestIncreasingSubsequenceLength(v):
    if len(v) == 0:  # boundry case
        return 0
 
    tail = [0 for i in range(len(v) + 1)]
    length = 1  # always points empty slot in tail
 
    tail[0] = v[0]
 
    for i in range(1, len(v)):
        if v[i] > tail[length-1]:
            # v[i] extends the largest subsequence
            tail[length] = v[i]
            length += 1
 
        else:
            # v[i] will extend a subsequence and discard older subsequence
 
            # find the largest value just smaller than v[i] in tail
 
            # to find that value do binary search for the v[i] in
            # the range from begin to 0 + length
 
            # bisect function either returns index where element is found
            # or the appropriate index at which element should be placed
 
            # finally replace the existing subsequene with new end value
            tail[bisect_left(tail, v[i], 0, length-1)] = v[i]
 
    return length
 
 
# Driver program to test above function
v = [2, 5, 3, 7, 11, 8, 10, 13, 6]
print("Length of Longest Increasing Subsequence is ",
      LongestIncreasingSubsequenceLength(v))
 
# This code is contributed by Serjeel Ranjan

Java

import java.io.*;
import java.lang.Math;
import java.util.*;
 
class LIS {
    static int LongestIncreasingSubsequenceLength(int v[])
    {
        if (v.length == 0) // boundry case
            return 0;
 
        int[] tail = new int[v.length];
        int length = 1; // always points empty slot in tail
        tail[0] = v[0];
 
        for (int i = 1; i < v.length; i++) {
 
            if (v[i] > tail[length - 1]) {
                // v[i] extends the largest subsequence
                tail[length++] = v[i];
            }
            else {
                // v[i] will extend a subsequence and
                // discard older subsequence
 
                // find the largest value just smaller than
                // v[i] in tail
 
                // to find that value do binary search for
                // the v[i] in the range from begin to 0 +
                // length
                int idx = Arrays.binarySearch(
                    tail, 0, length - 1, v[i]);
 
                // binarySearch in java returns negative
                // value if searched element is not found in
                // array
 
                // this negative value stores the
                // appropriate place where the element is
                // supposed to be stored
                if (idx < 0)
                    idx = -1 * idx - 1;
 
                // replacing the existing subsequene with
                // new end value
                tail[idx] = v[i];
            }
        }
        return length;
    }
 
    // Driver program to test above function
    public static void main(String[] args)
    {
        int v[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };
        System.out.println(
            "Length of Longest Increasing Subsequence is "
            + LongestIncreasingSubsequenceLength(v));
    }
}
 
/* This code is contributed by Serjeel Ranjan */

输出:

Length of Longest Increasing Subsequence is 6

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