Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何使用动态规划确定最长的递增子序列?_Algorithm_Computer Science_Dynamic Programming_Memoization_Lis - Fatal编程技术网

Algorithm 如何使用动态规划确定最长的递增子序列?

Algorithm 如何使用动态规划确定最长的递增子序列?,algorithm,computer-science,dynamic-programming,memoization,lis,Algorithm,Computer Science,Dynamic Programming,Memoization,Lis,我有一组整数。我想使用动态规划来找到该集合的大小。好的,我将首先描述最简单的解决方案,即O(N^2),其中N是集合的大小。还有一个O(N logn)解决方案,我也将描述它。在高效算法一节中查找它 我假设数组的索引是从0到N-1。因此,让我们将DP[i]定义为以索引i结束的LIS(最长递增子序列)的长度。为了计算DP[i],我们查看所有索引jDP[i]和array[j]是S中的最后一个元素,则parent[indexX]=indexlasteElement。这意味着最新元素的父元素是最后一个元素。

我有一组整数。我想使用动态规划来找到该集合的大小。

好的,我将首先描述最简单的解决方案,即O(N^2),其中N是集合的大小。还有一个O(N logn)解决方案,我也将描述它。在高效算法一节中查找它

我假设数组的索引是从0到N-1。因此,让我们将
DP[i]
定义为以索引
i
结束的LIS(最长递增子序列)的长度。为了计算
DP[i]
,我们查看所有索引
j
,并检查
DP[j]+1>DP[i]
array[j]
(我们希望它增加)。如果这是真的,我们可以为
DP[i]
更新当前最佳值。要找到数组的全局最优值,可以从
DP[0…N-1]
中获取最大值

int maxLength = 1, bestEnd = 0;
DP[0] = 1;
prev[0] = -1;

for (int i = 1; i < N; i++)
{
   DP[i] = 1;
   prev[i] = -1;

   for (int j = i - 1; j >= 0; j--)
      if (DP[j] + 1 > DP[i] && array[j] < array[i])
      {
         DP[i] = DP[j] + 1;
         prev[i] = j;
      }

   if (DP[i] > maxLength)
   {
      bestEnd = i;
      maxLength = DP[i];
   }
}
因此,LIS的长度是
5
(S的大小)

要重建实际的
LIS
,我们将再次使用父数组。 让
parent[i]
作为
LIS
中索引为
i
的元素的前导,以索引为
i
的元素结尾

为了使事情更简单,我们可以在数组中保留
S
,而不是实际的整数,而是它们在集合中的索引(位置)。我们不保留
{1,2,4,5,8}
,而是保留
{4,5,3,7,8}

即输入[4]=1,输入[5]=2,输入[3]=4,输入[7]=5,输入[8]=8

如果正确更新父阵列,则实际LIS为:

input[S[lastElementOfS]], 
input[parent[S[lastElementOfS]]],
input[parent[parent[S[lastElementOfS]]]],
........................................
现在我们来看一件重要的事情——如何更新父数组?有两种选择:

  • 如果
    X
    >是
    S
    中的最后一个元素,则
    parent[indexX]=indexlasteElement
    。这意味着最新元素的父元素是最后一个元素。我们只是把
    X
    放在
    S
    的末尾

  • 否则,找到
    S
    中最小元素的索引,即
    =
    大于
    X
    ,并将其更改为
    X
    。这里
    parent[indexX]=S[index-1]

    int maxLength = 1, bestEnd = 0;
    DP[0] = 1;
    prev[0] = -1;
    
    for (int i = 1; i < N; i++)
    {
       DP[i] = 1;
       prev[i] = -1;
    
       for (int j = i - 1; j >= 0; j--)
          if (DP[j] + 1 > DP[i] && array[j] < array[i])
          {
             DP[i] = DP[j] + 1;
             prev[i] = j;
          }
    
       if (DP[i] > maxLength)
       {
          bestEnd = i;
          maxLength = DP[i];
       }
    }
    

  • 下面的C++实现还包括一些代码,使用一个名为<>代码> PREV的数组来构建实际最长的子序列。

    std::vector<int> longest_increasing_subsequence (const std::vector<int>& s)
    {
        int best_end = 0;
        int sz = s.size();
    
        if (!sz)
            return std::vector<int>();
    
        std::vector<int> prev(sz,-1);
        std::vector<int> memo(sz, 0);
    
        int max_length = std::numeric_limits<int>::min();
    
        memo[0] = 1;
    
        for ( auto i = 1; i < sz; ++i)
        {
            for ( auto j = 0; j < i; ++j)
            {
                if ( s[j] < s[i] && memo[i] < memo[j] + 1 )
                {
                    memo[i] =  memo[j] + 1;
                    prev[i] =  j;
                }
            }
    
            if ( memo[i] > max_length ) 
            {
                best_end = i;
                max_length = memo[i];
            }
        }
    
        // Code that builds the longest increasing subsequence using "prev"
        std::vector<int> results;
        results.reserve(sz);
    
        std::stack<int> stk;
        int current = best_end;
    
        while (current != -1)
        {
            stk.push(s[current]);
            current = prev[current];
        }
    
        while (!stk.empty())
        {
            results.push_back(stk.top());
            stk.pop();
        }
    
        return results;
    }
    
    std::vector longest\u递增子序列(const std::vector&s)
    {
    int best_end=0;
    int sz=s.size();
    如果(!sz)
    返回std::vector();
    std::向量prev(sz,-1);
    标准:向量备忘录(sz,0);
    int max_length=std::numeric_limits::min();
    备注[0]=1;
    用于(自动i=1;i最大长度)
    {
    最佳端=i;
    最大长度=备忘录[i];
    }
    }
    //使用“prev”生成最长递增子序列的代码
    std::矢量结果;
    结果:储备量(sz);
    std::堆栈stk;
    int电流=最佳端;
    while(当前!=-1)
    {
    stk.push(s[当前]);
    当前=上一个[当前];
    }
    而(!stk.empty())
    {
    结果:推回(stk.top());
    stk.pop();
    }
    返回结果;
    }
    
    没有堆栈的实现只需反转向量

    #include <iostream>
    #include <vector>
    #include <limits>
    std::vector<int> LIS( const std::vector<int> &v ) {
      auto sz = v.size();
      if(!sz)
        return v;
      std::vector<int> memo(sz, 0);
      std::vector<int> prev(sz, -1);
      memo[0] = 1;
      int best_end = 0;
      int max_length = std::numeric_limits<int>::min();
      for (auto i = 1; i < sz; ++i) {
        for ( auto j = 0; j < i ; ++j) {
          if (s[j] < s[i] && memo[i] < memo[j] + 1) {
            memo[i] = memo[j] + 1;
            prev[i] = j;
          }
        }
        if(memo[i] > max_length) {
          best_end = i;
          max_length = memo[i];
        }
      }
    
      // create results
      std::vector<int> results;
      results.reserve(v.size());
      auto current = best_end;
      while (current != -1) {
        results.push_back(s[current]);
        current = prev[current];
      }
      std::reverse(results.begin(), results.end());
      return results;
    }
    
    #包括
    #包括
    #包括
    标准::向量LIS(常数标准::向量&v){
    自动sz=v.尺寸();
    如果(!sz)
    返回v;
    标准:向量备忘录(sz,0);
    std::向量prev(sz,-1);
    备注[0]=1;
    int best_end=0;
    int max_length=std::numeric_limits::min();
    用于(自动i=1;i最大长度){
    最佳端=i;
    最大长度=备忘录[i];
    }
    }
    //创造结果
    std::矢量结果;
    结果:储备量(v.size());
    自动电流=最佳端;
    while(当前!=-1){
    结果:推回(s[当前]);
    当前=上一个[当前];
    }
    std::reverse(results.begin(),results.end());
    返回结果;
    }
    
    Petar Minchev的解释帮助我澄清了问题,但我很难解析所有内容,因此我用过度描述性的变量名和大量注释制作了一个Python实现。我做了一个简单的递归解决方案,O(n^2)解决方案和O(n logn)解决方案

    func lcs(arr1 []int) int {
        arr2 := make([]int, len(arr1))
        for i, v := range arr1 {
            arr2[i] = v
        }
        sort.Ints(arr1)
        arr3 := []int{}
        prev := arr1[0] - 1
        for _, v := range arr1 {
            if v != prev {
                prev = v
                arr3 = append(arr3, v)
            }
        }
    
        n1, n2 := len(arr1), len(arr3)
    
        M := make([][]int, n2 + 1)
        e := make([]int, (n1 + 1) * (n2 + 1))
        for i := range M {
            M[i] = e[i * (n1 + 1):(i + 1) * (n1 + 1)]
        }
    
        for i := 1; i <= n2; i++ {
            for j := 1; j <= n1; j++ {
                if arr2[j - 1] == arr3[i - 1] {
                    M[i][j] = M[i - 1][j - 1] + 1
                } else if M[i - 1][j] > M[i][j - 1] {
                    M[i][j] = M[i - 1][j]
                } else {
                    M[i][j] = M[i][j - 1]
                }
            }
        }
    
        return M[n2][n1]
    }
    
    我希望这有助于清理算法

    递归解
    def递归_解决方案(剩余_序列,大于=无):
    “”“查找剩余的_序列中最长的递增子序列,该序列为
    大于大于并返回它。此解决方案为O(2^n)。“”“
    #基本情况:什么都没有了。
    如果len(剩余_序列)==0:
    返回剩余的\u序列
    #递归情况1:排除当前元素并处理剩余元素。
    最佳序列=递归解(剩余序列[1:],大于)
    #递归情况2:如果当前元素足够大,则包含它。
    第一个=剩余的_序列[0]
    如果(第一个>大于)或(大于等于无):
    带=[first]+递归解的序列(剩余的序列[1:],first)
    #选择案例1和案例2中较长的一个。
    如果len(序列带)>=len(最佳序列):
    最佳顺序=带有
    返回最佳_序列
    
    O(n^2)动态规划解
    def动态编程解决方案(顺序):
    “”“使用动态查找序列中最长的递增子序列。”
    
    def LIS(numlist):
        LS = [1]
        for i in range(1, len(numlist)):
            LS.append(1)
            for j in range(0, i):
                if numlist[i] > numlist[j] and LS[i]<=LS[j]:
                    LS[i] = 1 + LS[j]
        print LS
        return max(LS)
    
    numlist = map(int, raw_input().split(' '))
    print LIS(numlist)
    
    object Solve {
      def longestIncrSubseq[T](xs: List[T])(implicit ord: Ordering[T]) = {
        xs.foldLeft(List[(Int, List[T])]()) {
          (sofar, x) =>
            if (sofar.isEmpty) List((1, List(x)))
            else {
              val resIfEndsAtCurr = (sofar, xs).zipped map {
                (tp, y) =>
                  val len = tp._1
                  val seq = tp._2
                  if (ord.lteq(y, x)) {
                    (len + 1, x :: seq) // reversely recorded to avoid O(n)
                  } else {
                    (1, List(x))
                  }
              }
              sofar :+ resIfEndsAtCurr.maxBy(_._1)
            }
        }.maxBy(_._1)._2.reverse
      }
    
      def main(args: Array[String]) = {
        println(longestIncrSubseq(List(
          0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15)))
      }
    }
    
    public static void olis(int[] seq){
    
        int[] memo = new int[seq.length];
    
        memo[0] = seq[0];
        int pos = 0;
    
        for (int i=1; i<seq.length; i++){
    
            int x = seq[i];
    
                if (memo[pos] < x){ 
                    pos++;
                    memo[pos] = x;
                } else {
    
                    for(int j=0; j<=pos; j++){
                        if (memo[j] >= x){
                            memo[j] = x;
                            break;
                        }
                    }
                }
                //just to print every step
                System.out.println(Arrays.toString(memo));
        }
    
        //the final array with the LIS
        System.out.println(Arrays.toString(memo));
        System.out.println("The length of lis is " + (pos + 1));
    
    }
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    
    /**
     * Created by Shreyans on 4/16/2015
     */
    
    class LNG_INC_SUB//Longest Increasing Subsequence
    {
        public static void main(String[] args) throws Exception
        {
            BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
            System.out.println("Enter Numbers Separated by Spaces to find their LIS\n");
            String[] s1=br.readLine().split(" ");
            int n=s1.length;
            int[] a=new int[n];//Array actual of Numbers
            String []ls=new String[n];// Array of Strings to maintain LIS for every element
            for(int i=0;i<n;i++)
            {
                a[i]=Integer.parseInt(s1[i]);
            }
            int[]dp=new int[n];//Storing length of max subseq.
            int max=dp[0]=1;//Defaults
            String seq=ls[0]=s1[0];//Defaults
            for(int i=1;i<n;i++)
            {
                dp[i]=1;
                String x="";
                for(int j=i-1;j>=0;j--)
                {
                    //First check if number at index j is less than num at i.
                    // Second the length of that DP should be greater than dp[i]
                    // -1 since dp of previous could also be one. So we compare the dp[i] as empty initially
                    if(a[j]<a[i]&&dp[j]>dp[i]-1)
                    {
                        dp[i]=dp[j]+1;//Assigning temp length of LIS. There may come along a bigger LIS of a future a[j]
                        x=ls[j];//Assigning temp LIS of a[j]. Will append a[i] later on
                    }
                }
                x+=(" "+a[i]);
                ls[i]=x;
                if(dp[i]>max)
                {
                    max=dp[i];
                    seq=ls[i];
                }
            }
            System.out.println("Length of LIS is: " + max + "\nThe Sequence is: " + seq);
        }
    }
    
    import java.util.Scanner;
    
    public class LongestIncreasingSeq {
    
    
        private static int binarySearch(int table[],int a,int len){
    
            int end = len-1;
            int beg = 0;
            int mid = 0;
            int result = -1;
            while(beg <= end){
                mid = (end + beg) / 2;
                if(table[mid] < a){
                    beg=mid+1;
                    result = mid;
                }else if(table[mid] == a){
                    return len-1;
                }else{
                    end = mid-1;
                }
            }
            return result;
        }
        
        public static void main(String[] args) {        
            
    //        int[] t = {1, 2, 5,9,16};
    //        System.out.println(binarySearch(t , 9, 5));
            Scanner in = new Scanner(System.in);
            int size = in.nextInt();//4;
            
            int A[] = new int[size];
            int table[] = new int[A.length]; 
            int k = 0;
            while(k<size){
                A[k++] = in.nextInt();
                if(k<size-1)
                    in.nextLine();
            }        
            table[0] = A[0];
            int len = 1; 
            for (int i = 1; i < A.length; i++) {
                if(table[0] > A[i]){
                    table[0] = A[i];
                }else if(table[len-1]<A[i]){
                    table[len++]=A[i];
                }else{
                    table[binarySearch(table, A[i],len)+1] = A[i];
                }            
            }
            System.out.println(len);
        }    
    }
    
    /**
     **    Java Program to implement Longest Increasing Subsequence Algorithm
     **/
    
    import java.util.Scanner;
    
    /** Class  LongestIncreasingSubsequence **/
     class  LongestIncreasingSubsequence
    {
        /** function lis **/
        public int[] lis(int[] X)
        {        
            int n = X.length - 1;
            int[] M = new int[n + 1];  
            int[] P = new int[n + 1]; 
            int L = 0;
    
            for (int i = 1; i < n + 1; i++)
            {
                int j = 0;
    
                /** Linear search applied here. Binary Search can be applied too.
                    binary search for the largest positive j <= L such that 
                    X[M[j]] < X[i] (or set j = 0 if no such value exists) **/
    
                for (int pos = L ; pos >= 1; pos--)
                {
                    if (X[M[pos]] < X[i])
                    {
                        j = pos;
                        break;
                    }
                }            
                P[i] = M[j];
                if (j == L || X[i] < X[M[j + 1]])
                {
                    M[j + 1] = i;
                    L = Math.max(L,j + 1);
                }
            }
    
            /** backtrack **/
    
            int[] result = new int[L];
            int pos = M[L];
            for (int i = L - 1; i >= 0; i--)
            {
                result[i] = X[pos];
                pos = P[pos];
            }
            return result;             
        }
    
        /** Main Function **/
        public static void main(String[] args) 
        {    
            Scanner scan = new Scanner(System.in);
            System.out.println("Longest Increasing Subsequence Algorithm Test\n");
    
            System.out.println("Enter number of elements");
            int n = scan.nextInt();
            int[] arr = new int[n + 1];
            System.out.println("\nEnter "+ n +" elements");
            for (int i = 1; i <= n; i++)
                arr[i] = scan.nextInt();
    
            LongestIncreasingSubsequence obj = new LongestIncreasingSubsequence(); 
            int[] result = obj.lis(arr);       
    
            /** print result **/ 
    
            System.out.print("\nLongest Increasing Subsequence : ");
            for (int i = 0; i < result.length; i++)
                System.out.print(result[i] +" ");
            System.out.println();
        }
    }
    
    def LIS(S):
        T = sort(S)
        T = removeDuplicates(T)
        return LCS(S, T)
    
    func lcs(arr1 []int) int {
        arr2 := make([]int, len(arr1))
        for i, v := range arr1 {
            arr2[i] = v
        }
        sort.Ints(arr1)
        arr3 := []int{}
        prev := arr1[0] - 1
        for _, v := range arr1 {
            if v != prev {
                prev = v
                arr3 = append(arr3, v)
            }
        }
    
        n1, n2 := len(arr1), len(arr3)
    
        M := make([][]int, n2 + 1)
        e := make([]int, (n1 + 1) * (n2 + 1))
        for i := range M {
            M[i] = e[i * (n1 + 1):(i + 1) * (n1 + 1)]
        }
    
        for i := 1; i <= n2; i++ {
            for j := 1; j <= n1; j++ {
                if arr2[j - 1] == arr3[i - 1] {
                    M[i][j] = M[i - 1][j - 1] + 1
                } else if M[i - 1][j] > M[i][j - 1] {
                    M[i][j] = M[i - 1][j]
                } else {
                    M[i][j] = M[i][j - 1]
                }
            }
        }
    
        return M[n2][n1]
    }
    
    void LIS(int arr[]){
            int maxCount[]=new int[arr.length];
            int link[]=new int[arr.length];
            int maxI=0;
            link[0]=0;
            maxCount[0]=0;
    
            for (int i = 1; i < arr.length; i++) {
                for (int j = 0; j < i; j++) {
                    if(arr[j]<arr[i] && ((maxCount[j]+1)>maxCount[i])){
                        maxCount[i]=maxCount[j]+1;
                        link[i]=j;
                        if(maxCount[i]>maxCount[maxI]){
                            maxI=i;
                        }
                    }
                }
            }
    
    
            for (int i = 0; i < link.length; i++) {
                System.out.println(arr[i]+"   "+link[i]);
            }
            print(arr,maxI,link);
    
        }
    
        void print(int arr[],int index,int link[]){
            if(link[index]==index){
                System.out.println(arr[index]+" ");
                return;
            }else{
                print(arr, link[index], link);
                System.out.println(arr[index]+" ");
            }
        }
    
    def longestincrsub(arr1):
        n=len(arr1)
        l=[1]*n
        for i in range(0,n):
            for j in range(0,i)  :
                if arr1[j]<arr1[i] and l[i]<l[j] + 1:
                    l[i] =l[j] + 1
        l.sort()
        return l[-1]
    arr1=[10,22,9,33,21,50,41,60]
    a=longestincrsub(arr1)
    print(a)
    
    class Solution:
        def binary_search(self,s,x):
            low=0
            high=len(s)-1
            flag=1
            while low<=high:
                  mid=(high+low)//2
                  if s[mid]==x:
                     flag=0
                     break
                  elif s[mid]<x:
                      low=mid+1
                  else:
                     high=mid-1
            if flag:
               s[low]=x
            return s
    
        def lengthOfLIS(self, nums: List[int]) -> int:
             if not nums:
                return 0
             s=[]
             s.append(nums[0])
             for i in range(1,len(nums)):
                 if s[-1]<nums[i]:
                    s.append(nums[i])
                 else:
                     s=self.binary_search(s,nums[i])
             return len(s)
    
    #include <iostream>
    #include "vector"
    using namespace std;
    
    // binary search (If value not found then it will return the index where the value should be inserted)
    int ceilBinarySearch(vector<int> &a,int beg,int end,int value)
    {
        if(beg<=end)
        {
            int mid = (beg+end)/2;
            if(a[mid] == value)
                return mid;
            else if(value < a[mid])
                return ceilBinarySearch(a,beg,mid-1,value);
            else
                return ceilBinarySearch(a,mid+1,end,value);
    
        return 0;
        }
    
        return beg;
    
    }
    int lis(vector<int> arr)
    {
        vector<int> dp(arr.size(),0);
        int len = 0;
        for(int i = 0;i<arr.size();i++)
        {
            int j = ceilBinarySearch(dp,0,len-1,arr[i]);
            dp[j] = arr[i];
            if(j == len)
                len++;
    
        }
        return len;
    }
    
    int main()
    {
        vector<int> arr  {2, 5,-1,0,6,1,2};
        cout<<lis(arr);
        return 0;
    }
    
    import java.util.*;
    
    class ChainHighestValue implements Comparable<ChainHighestValue>{
        int highestValue;
        int chainLength;
        ChainHighestValue(int highestValue,int chainLength) {
            this.highestValue = highestValue;
            this.chainLength = chainLength;
        }
        @Override
        public int compareTo(ChainHighestValue o) {
           return this.chainLength-o.chainLength;
        }
    
    }
    
    
    public class LongestIncreasingSubsequenceLinkedList {
    
    
        private static LinkedList<Integer> LongestSubsequent(int arr[], int size){
            ArrayList<LinkedList<Integer>> seqList=new ArrayList<>();
            ArrayList<ChainHighestValue> valuePairs=new ArrayList<>();
            for(int i=0;i<size;i++){
                int currValue=arr[i];
                if(valuePairs.size()==0){
                    LinkedList<Integer> aList=new LinkedList<>();
                    aList.add(arr[i]);
                    seqList.add(aList);
                    valuePairs.add(new ChainHighestValue(arr[i],1));
    
                }else{
                    try{
                        ChainHighestValue heighestIndex=valuePairs.stream().filter(e->e.highestValue<currValue).max(ChainHighestValue::compareTo).get();
                        int index=valuePairs.indexOf(heighestIndex);
                        seqList.get(index).add(arr[i]);
                        heighestIndex.highestValue=arr[i];
                        heighestIndex.chainLength+=1;
    
                    }catch (Exception e){
                        LinkedList<Integer> aList=new LinkedList<>();
                        aList.add(arr[i]);
                        seqList.add(aList);
                        valuePairs.add(new ChainHighestValue(arr[i],1));
                    }
                }
            }
            ChainHighestValue heighestIndex=valuePairs.stream().max(ChainHighestValue::compareTo).get();
            int index=valuePairs.indexOf(heighestIndex);
            return seqList.get(index);
        }
    
        public static void main(String[] args){
            int arry[]={5,1,3,6,11,30,32,5,3,73,79};
            //int arryB[]={3,1,5,2,6,4,9};
            LinkedList<Integer> LIS=LongestSubsequent(arry, arry.length);
            System.out.println("Longest Incrementing Subsequence:");
            for(Integer a: LIS){
                System.out.print(a+" ");
            }
    
        }
    }
    
    package com.company.dynamicProgramming;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class LongestIncreasingSequence {
    
        static int complexity = 0;
    
        public static void main(String ...args){
    
    
            int[] arr = {10, 22, 9, 33, 21, 50, 41, 60, 80};
            int n = arr.length;
    
            Map<Integer, Integer> memo = new HashMap<>();
    
            lis(arr, n, memo);
    
            //Display Code Begins
            int x = 0;
            System.out.format("Longest Increasing Sub-Sequence with size %S is -> ",memo.get(n));
            for(Map.Entry e : memo.entrySet()){
    
                if((Integer)e.getValue() > x){
                    System.out.print(arr[(Integer)e.getKey()-1] + " ");
                    x++;
                }
            }
            System.out.format("%nAnd Time Complexity for Array size %S is just %S ", arr.length, complexity );
            System.out.format( "%nWhich is equivalent to O(n Log n) i.e. %SLog(base2)%S is %S",arr.length,arr.length, arr.length * Math.ceil(Math.log(arr.length)/Math.log(2)));
            //Display Code Ends
    
        }
    
    
    
        static int lis(int[] arr, int n, Map<Integer, Integer> memo){
    
            if(n==1){
                memo.put(1, 1);
                return 1;
            }
    
            int lisAti;
            int lisAtn = 1;
    
            for(int i = 1; i < n; i++){
                complexity++;
    
                if(memo.get(i)!=null){
                    lisAti = memo.get(i);
                }else {
                    lisAti = lis(arr, i, memo);
                }
    
                if(arr[i-1] < arr[n-1] && lisAti +1 > lisAtn){
                    lisAtn = lisAti +1;
                }
            }
    
            memo.put(n, lisAtn);
            return lisAtn;
    
        }
    }
    
    
    Longest Increasing Sub-Sequence with size 6 is -> 10 22 33 50 60 80 
    And Time Complexity for Array size 9 is just 36 
    Which is equivalent to O(n Log n) i.e. 9Log(base2)9 is 36.0
    Process finished with exit code 0
    
    
    #include <bits/stdc++.h> // gcc supported header to include (almost) everything
    using namespace std;
    typedef long long ll;
    
    int main()
    {
      ll n;
      cin >> n;
      ll arr[n];
      set<ll> S;
    
      for(ll i=0; i<n; i++)
      {
        cin >> arr[i];
        auto it = S.lower_bound(arr[i]);
        if(it != S.end())
          S.erase(it);
        S.insert(arr[i]);
      }
    
      cout << S.size() << endl; // Size of the set is the required answer
    
      return 0;
    }
    
    public int lengthOfLIS(int[] nums) {
                return LIS(nums,Integer.MIN_VALUE, 0,new HashMap<>()) -1;
        }
        public int LIS(int[] arr, int value, int nextIndex, Map<String,Integer> memo){
            if(memo.containsKey(value+","+nextIndex))return memo.get(value+","+nextIndex);
            if(nextIndex >= arr.length)return 1;
    
            int max = Integer.MIN_VALUE;
            for(int i=nextIndex; i<arr.length; i++){
                if(arr[i] > value){
                    max = Math.max(max,LIS(arr,arr[i],i+1,memo));
                }
            }
            if(max == Integer.MIN_VALUE)return 1;
            max++;
            memo.put(value+","+nextIndex,max);
            return max;
        }