Open In App

Number of Longest Increasing Subsequences

Last Updated : 11 Apr, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] of size N, the task is to count the number of longest increasing subsequences present in the given array.

Examples:

Input: arr[] = {2, 2, 2, 2, 2}
Output: 5
Explanation: The length of the longest increasing subsequence is 1, i.e. {2}. Therefore, count of longest increasing subsequences of length 1 is 5.

Input: arr[] = {1, 3, 5, 4, 7}
Output: 2
Explanation: The length of the longest increasing subsequence is 4, and there are 2 longest increasing subsequences of length 4, i.e. {1, 3, 4, 7} and {1, 3, 5, 7}.

Naive Approach: The simplest approach is to generate all possible subsequences present in the given array arr[] and count the increasing subsequences of maximum length. Print the count after checking all subsequences. 

Time Complexity: O(N*2N)
Auxiliary Space: O(1)

Efficient Approach: To optimize the above approach, the idea is to use Dynamic Programming as the above problem has overlapping subproblems that need to be calculated more than once, and to reduce that calculation use tabulation or memoization. Follow the steps below to solve the problem:

  • Initialize two arrays dp_l[] and dp_c[] to store the length of the longest increasing subsequences and the count of the longest increasing subsequence at each index respectively.
  • Iterate over the range [1, N – 1] using the variable i:
    • Iterate over the range [0, i – 1] using the variable j:
      • If arr[i] > arr[j] then check for the following cases:
                ~ If (dp_l[j]+1) greater than dp_l[i], then update dp_l[i] as dp_l[j] + 1 and dp_c[i] as dp_c[j]
                ~ Else if (dp_l[j] + 1) is the same as dp_l[i], then update dp_c[i] as dp_c[i] + dp_c[j].
  • Find the maximum element in the array dp_l[] and store it in a variable max_length that will give the length of LIS.
  • Initialize a variable count with 0 to store the number of the longest increasing subsequence.
  • Traverse the array dp_l[] and if at any index idx, dp_l[idx] is the same as max_length then increment the count by dp_c[idx].
  • After the above steps, print the value of count, which is the number of longest increasing subsequences in the given array.

Below is the implementation of the above approach:

C++




// C++ program for the
// above approach
#include <bits/stdc++.h>
using namespace std;
 
//Function to count the number
// of LIS in the array nums[]
int findNumberOfLIS(vector<int> nums)
{
  //Base Case
  if (nums.size() == 0)
    return 0;
 
  int n = nums.size();
 
  //Initialize dp_l array with
  // 1s
  vector<int> dp_l(n, 1);
 
  //Initialize dp_c array with
  // 1s
  vector<int> dp_c(n, 1);
 
  for (int i = 0; i < n; i++)
  {
    for (int j = 0; j < i; j++)
    {
      //If current element is
      // smaller
      if (nums[i] <= nums[j])
        continue;
 
      if  (dp_l[j] + 1 > dp_l[i])
      {
        dp_l[i] = dp_l[j] + 1;
        dp_c[i] = dp_c[j];
      }
      else if (dp_l[j] + 1 == dp_l[i])
        dp_c[i] += dp_c[j];
    }
  }
 
  //Store the maximum element
  // from dp_l
  int max_length = 0;
 
  for (int i : dp_l)
    max_length = max(i,max_length);
 
  //Stores the count of LIS
  int count = 0;
 
  //Traverse dp_l and dp_c
  // simultaneously
  for(int i = 0; i < n; i++)
  {
    //Update the count
    if (dp_l[i] == max_length)
      count += dp_c[i];
  }
   
  //Return the count of LIS
  return count;
}
 
//Driver code
int main()
{
  //Given array arr[]
  vector<int> arr = {1, 3, 5, 4, 7};
 
  //Function Call
  cout << findNumberOfLIS(arr) << endl;
}
 
// This code is contributed by Mohit Kumar 29


Java




// Java program for the
// above approach
import java.util.*;
 
class GFG{
 
// Function to count the number
// of LIS in the array nums[]
static int findNumberOfLIS(int[] nums)
{
   
  // Base Case
  if (nums.length == 0)
      return 0;
   
  int n = nums.length;
   
  // Initialize dp_l array with
  // 1s
  int[] dp_l = new int[n];
  Arrays.fill(dp_l, 1);
 
  // Initialize dp_c array with
  // 1s
  int[] dp_c = new int[n];
  Arrays.fill(dp_c, 1);
 
  for(int i = 0; i < n; i++)
  {
    for(int j = 0; j < i; j++)
    {
       
      // If current element is
      // smaller
      if (nums[i] <= nums[j])
        continue;
 
      if (dp_l[j] + 1 > dp_l[i])
      {
        dp_l[i] = dp_l[j] + 1;
        dp_c[i] = dp_c[j];
      }
      else if (dp_l[j] + 1 == dp_l[i])
        dp_c[i] += dp_c[j];
    }
  }
 
  // Store the maximum element
  // from dp_l
  int max_length = 0;
 
  for(int i : dp_l)
    max_length = Math.max(i, max_length);
 
  // Stores the count of LIS
  int count = 0;
 
  // Traverse dp_l and dp_c
  // simultaneously
  for(int i = 0; i < n; i++)
  {
     
    // Update the count
    if (dp_l[i] == max_length)
      count += dp_c[i];
  }
   
  // Return the count of LIS
  return count;
}
 
// Driver code
public static void main(String[] args)
{
   
  // Given array arr[]
  int[] arr = { 1, 3, 5, 4, 7 };
 
  // Function Call
  System.out.print(findNumberOfLIS(arr) + "\n");
}
}
 
// This code is contributed by shikhasingrajput


Python3




# Python3 program for the above approach
 
# Function to count the number of LIS
# in the array nums[]
def findNumberOfLIS(nums):
 
    # Base Case
    if not nums:
        return 0
 
    n = len(nums)
 
    # Initialize dp_l array with 1s
    dp_l = [1] * n
 
    # Initialize dp_c array with 1s
    dp_c = [1] * n
 
    for i, num in enumerate(nums):
        for j in range(i):
 
            # If current element is smaller
            if nums[i] <= nums[j]:
                continue
 
            # Otherwise
            if dp_l[j] + 1 > dp_l[i]:
                dp_l[i] = dp_l[j] + 1
                dp_c[i] = dp_c[j]
 
            elif dp_l[j] + 1 == dp_l[i]:
                dp_c[i] += dp_c[j]
 
    # Store the maximum element from dp_l
    max_length = max(x for x in dp_l)
 
    # Stores the count of LIS
    count = 0
 
    # Traverse dp_l and dp_c simultaneously
    for l, c in zip(dp_l, dp_c):
 
        # Update the count
        if l == max_length:
            count += c
 
    # Return the count of LIS
    return count
 
# Driver Code
 
# Given array arr[]
arr = [1, 3, 5, 4, 7]
 
# Function Call
print(findNumberOfLIS(arr))


C#




// C# program to implement
// the above approach
using System;
using System.Collections.Generic;
class GFG {
     
    // Function to count the number
    // of LIS in the array nums[]
    static int findNumberOfLIS(int[] nums)
    {
        
      // Base Case
      if (nums.Length == 0)
          return 0;
        
      int n = nums.Length;
        
      // Initialize dp_l array with
      // 1s
      int[] dp_l = new int[n];
      Array.Fill(dp_l, 1);
      
      // Initialize dp_c array with
      // 1s
      int[] dp_c = new int[n];
      Array.Fill(dp_c, 1);
      
      for(int i = 0; i < n; i++)
      {
        for(int j = 0; j < i; j++)
        {
            
          // If current element is
          // smaller
          if (nums[i] <= nums[j])
            continue;
      
          if (dp_l[j] + 1 > dp_l[i])
          {
            dp_l[i] = dp_l[j] + 1;
            dp_c[i] = dp_c[j];
          }
          else if (dp_l[j] + 1 == dp_l[i])
            dp_c[i] += dp_c[j];
        }
      }
      
      // Store the maximum element
      // from dp_l
      int max_length = 0;
      
      foreach(int i in dp_l)
        max_length = Math.Max(i, max_length);
      
      // Stores the count of LIS
      int count = 0;
      
      // Traverse dp_l and dp_c
      // simultaneously
      for(int i = 0; i < n; i++)
      {
          
        // Update the count
        if (dp_l[i] == max_length)
          count += dp_c[i];
      }
        
      // Return the count of LIS
      return count;
    }
 
  // Driver code
  static void Main() {
       
      // Given array arr[]
      int[] arr = { 1, 3, 5, 4, 7 };
      
      // Function Call
      Console.WriteLine(findNumberOfLIS(arr));
  }
}
 
// This code is contributed by divyeshrabadiya07


Javascript




<script>
 
// Javascript program for the
// above approach
 
// Function to count the number
// of LIS in the array nums[]
function findNumberOfLIS(nums)
{
  //Base Case
  if (nums.length == 0)
    return 0;
 
  var n = nums.length;
 
  // Initialize dp_l array with
  // 1s
  var dp_l = Array(n).fill(1);
 
  // Initialize dp_c array with
  // 1s
  var dp_c = Array(n).fill(1);
 
  for (var i = 0; i < n; i++)
  {
    for (var j = 0; j < i; j++)
    {
      // If current element is
      // smaller
      if (nums[i] <= nums[j])
        continue;
 
      if  (dp_l[j] + 1 > dp_l[i])
      {
        dp_l[i] = dp_l[j] + 1;
        dp_c[i] = dp_c[j];
      }
      else if (dp_l[j] + 1 == dp_l[i])
        dp_c[i] += dp_c[j];
    }
  }
 
  // Store the maximum element
  // from dp_l
  var max_length = 0;
 
  dp_l.forEach(i => {
       
    max_length = Math.max(i,max_length);
  });
 
  // Stores the count of LIS
  var count = 0;
 
  //Traverse dp_l and dp_c
  // simultaneously
  for(var i = 0; i < n; i++)
  {
    // Update the count
    if (dp_l[i] == max_length)
      count += dp_c[i];
  }
   
  // Return the count of LIS
  return count;
}
 
// Driver code
// Given array arr[]
var arr = [1, 3, 5, 4, 7];
 
// Function Call
document.write( findNumberOfLIS(arr));
 
// This code is contributed by rutvik_56.
</script>


Output

2

Time Complexity: O(N2)
Auxiliary Space: O(N)

Segment Tree Approach

We can solve this problem using segment trees. The idea is to build a segment tree and then querying for the range [0,arr[i]-1]. The reason is arr[i] can append to any number which is less than it to make a increasing subsequence. 

For example if arr[i]=5, arr[i] can append after 0,1,2,3,4 to make increasing subsequence. This logic is what we will try to implement using a segment Tree. We will have a segment tree having nodes containing a pair. The pair contains the LIS length, ways ending at node. Our result would be at the root of the tree. 

We make the segment Tree using the maximum value in the array. If it is too large, then we need to step it down using RANKING method. For example, {9,1,4,2} and {3,0,2,1} have the same LIS counts. It is because if you observe, the ordering is the same. We can exploit this idea to minimize the space requirement in our segment Tree to just O(4*N), where N is the size of the array.

Let us briefly go over the implementation of ranking arrangement.

Given arr = [1,9,100,2,2]

Copy the arr in a new array temp and sort temp array

temp = [1,2,2,9,100]

Now, maintain a mx variable initialized to zero. Store the ]element , mx], if it not present in the map and increment mx.

Map -> 1 , 0

             2 , 1

             9 , 2

         100 , 3

Iterate on arr , and place the corresponding value from the map

arr = [0,2,3,1,1]

This is our new stepped down array. This technique is very useful when only the ordering of elements matter more than the value of element. 

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
vector<pair<int, int>> tree; // pair<int,int> = MxLength,ways
 
int RANKER(vector<int>& nums) {
    int n=nums.size();
   
    vector<int> temp=nums;
    sort(temp.begin(),temp.end());
         
    unordered_map<int,int> rank;
    int mx=0;
         
    for(int i=0;i<n;i++){
       if(rank.find(temp[i])==rank.end()){
          rank[temp[i]]=mx++;
       }
    }
     
    for(int i=0;i<n;i++){
        nums[i]=rank[nums[i]];
    }
   
      return mx;
}
 
pair<int, int> chooseBest(pair<int, int>& left, pair<int, int>& right) {
    // We will choose the longest length LIS's ways.
        pair<int, int> res;
 
    int mxLen_LFT = left.first;
    int ways_LFT = left.second;
 
    int mxLen_RHT = right.first;
    int ways_RHT = right.second;
 
    if (mxLen_LFT > mxLen_RHT) {
        res = { mxLen_LFT, ways_LFT };
    }
    else if (mxLen_LFT < mxLen_RHT) {
        res = { mxLen_RHT, ways_RHT };
    }
    else { // same length, so we will add up the ways
        res.first = mxLen_LFT;
        res.second = ways_LFT + ways_RHT;
    }
    return res;
}
 
void update(int start, int end, int parent, int element, int mxLength, int ways) {
    if (start == end) {
        if (tree[parent].first == mxLength) {
            // if same maxlength is achieved again, add ways
            tree[parent].second += ways;
        }
        else { // if achieved more length, update length and ways
            tree[parent] = { mxLength, ways };
        }
        return;
    }
    int mid = (start + end) / 2;
   
    if (element <= mid) {
        update(start, mid, 2 * parent + 1, element, mxLength, ways);
    }
    else {
        update(mid + 1, end, 2 * parent + 2, element, mxLength, ways);
    }
   
    tree[parent] = chooseBest(tree[2 * parent + 1], tree[2 * parent + 2]);
}
 
pair<int, int> maxLen(int start, int end, int qstart, int qend, int parent) {
    if (start > qend || end < qstart) {
        return { 0, 0 };
    }
    if (start >= qstart && end <= qend) {
        return tree[parent];
    }
    int mid = (start + end) / 2;
    pair<int, int> left = maxLen(start, mid, qstart, qend, 2 * parent + 1);
    pair<int, int> right = maxLen(mid + 1, end, qstart, qend, 2 * parent + 2);
    return chooseBest(left, right);
}
 
int findNumberOfLIS(vector<int>& nums) {
    int n=nums.size();
     
    int mx=RANKER(nums); // step down the array
 
    /*
        cout<<"Step down array -> ";
        for(auto c: nums){
            cout<<c<<" ";
        }
        cout<<endl<<endl;
   */
 
    tree.resize(4 * mx + 5);
 
    for (int i = 0; i < n; i++) {
        /* As each element can be a subseq in itself with len=1 and way=1 to form itself*/
       
        int mxLen = 1; // mxLen- maximum length achieved for this index
        int ways = 1; // ways- number of ways to achieve mxLen at this index
 
        if (nums[i] > 0) {
            pair<int, int> info = maxLen(0, mx, 0, nums[i] - 1, 0);
            if (info.first + 1 > mxLen) { // +1 because nums[i] is getting appended
                mxLen = info.first + 1;
                ways = info.second;
            }
        }
 
        /*
            cout<<"largest increasing length ending at index-"<<i<<" is "<<mxLen<<endl;
            cout<<"Number of ways is "<<ways<<endl<<endl;
        */
 
        update(0, mx, 0, nums[i], mxLen, ways); // update the largest len and the ways for nums[i]
    }
    return tree[0].second; // return ways from root of the tree
}
 
int main()
{
 
     //Given array arr[]
      vector<int> arr = {1, 3, 5, 4, 7};
  
      //Function Call
      cout << findNumberOfLIS(arr) << endl;
}
 
// Code by RainX (Abhijit Roy, NIT AGARTALA)


Java




// Java code addition
import java.util.*;
 
class LIS {
  public static int ranker(int[] nums) {
    int n = nums.length;
    int[] temp = Arrays.copyOf(nums, n);
    Arrays.sort(temp);
    Map<Integer, Integer> rank = new HashMap<>();
    int mx = 0;
    for (int i = 0; i < n; i++) {
      if (!rank.containsKey(temp[i])) {
        rank.put(temp[i], mx);
        mx++;
      }
    }
    for (int i = 0; i < n; i++) {
      nums[i] = rank.get(nums[i]);
    }
    return mx;
  }
 
  public static int[] chooseBest(int[] left, int[] right) {
    // We will choose the longest length LIS's ways.
    int mxLen_LFT = left[0];
    int ways_LFT = left[1];
    int mxLen_RHT = right[0];
    int ways_RHT = right[1];
    if (mxLen_LFT > mxLen_RHT) {
      return new int[]{mxLen_LFT, ways_LFT};
    } else if (mxLen_LFT < mxLen_RHT) {
      return new int[]{mxLen_RHT, ways_RHT};
    } else {// same length, so we will add up the ways
      return new int[]{mxLen_LFT, ways_LFT + ways_RHT};
    }
  }
 
  public static void update(int start, int end, int parent, int element, int mxLength, int ways, int[][] tree) {
    if (start == end) { // if same maxlength is achieved again, add ways
      if (tree[parent][0] == mxLength) {
        tree[parent][1] += ways;
      } else {// if achieved more length, update length and ways
        tree[parent][0] = mxLength;
        tree[parent][1] = ways;
      }
      return;
    }
    int mid = (start + end) / 2;
    if (element <= mid) {
      update(start, mid, 2 * parent + 1, element, mxLength, ways, tree);
    } else {
      update(mid + 1, end, 2 * parent + 2, element, mxLength, ways, tree);
    }
    tree[parent] = chooseBest(tree[2 * parent + 1], tree[2 * parent + 2]);
  }
 
  public static int[] maxLen(int start, int end, int qstart, int qend, int parent, int[][] tree) {
    if (start > qend || end < qstart) {
      return new int[]{0, 0};
    }
    if (start >= qstart && end <= qend) {
      return tree[parent];
    }
    int mid = (start + end) / 2;
    int[] left = maxLen(start, mid, qstart, qend, 2 * parent + 1, tree);
    int[] right = maxLen(mid + 1, end, qstart, qend, 2 * parent + 2, tree);
    return chooseBest(left, right);
  }
 
  public static int findNumberOfLIS(int[] nums) {
    int n = nums.length;
    int mx = ranker(nums);  // step down the array
    /*
        cout<<"Step down array -> ";
        for(auto c: nums){
            cout<<c<<" ";
        }
        cout<<endl<<endl;
   */
    int[][] tree = new int[4 * mx + 5][2];
    for (int i = 0; i < n; i++) {
      /* As each element can be a subseq in itself with len=1 and way=1 to form itself*/
      int mxLen = 1;// mxLen- maximum length achieved for this index
      int ways = 1; // ways- number of ways to achieve mxLen at this index
      if (nums[i] > 0) {
        int[] info = maxLen(0, mx, 0, nums[i] - 1, 0, tree);
        if (info[0] + 1 > mxLen) {
          mxLen = info[0] + 1;
          ways = info[1];
        }
      }
 
      /*
            cout<<"largest increasing length ending at index-"<<i<<" is "<<mxLen<<endl;
            cout<<"Number of ways is "<<ways<<endl<<endl;
        */
      update(0, mx, 0, nums[i], mxLen, ways, tree); // update the largest len and the ways for nums[i]
    }
    return tree[0][1]; // return ways from root of the tree
  }
 
  public static void main(String[] args){
 
    //Given array arr[]
    int[] arr = {1, 3, 5, 4, 7};
 
    // Function call.
    System.out.println(findNumberOfLIS(arr));
  }
}
 
// The code is contributed by Arushi Goel.


Python3




def RANKER(nums):
      # Rank the elements in the array from 0 to n-1 based on their values,
    # returns the number of distinct elements in the array.
    n = len(nums)
    temp = nums.copy()
    temp.sort()
    rank = {}
    mx = 0
    for i in range(n):
        if temp[i] not in rank:
            rank[temp[i]] = mx
            mx += 1
    for i in range(n):
        nums[i] = rank[nums[i]]
    return mx
 
def chooseBest(left, right):
      # Given two pairs, return the pair that has the longer maximum length,
    # and if they have the same maximum length, add their ways together.
    mxLen_LFT, ways_LFT = left
    mxLen_RHT, ways_RHT = right
    if mxLen_LFT > mxLen_RHT:
        res = (mxLen_LFT, ways_LFT)
    elif mxLen_LFT < mxLen_RHT:
        res = (mxLen_RHT, ways_RHT)
    else:
        res = (mxLen_LFT, ways_LFT + ways_RHT)
    return res
 
def update(start, end, parent, element, mxLength, ways, tree):
      # Update the segment tree to reflect the new element added to the array.
    if start == end:
        if tree[parent][0] == mxLength:
            tree[parent] = (mxLength, tree[parent][1] + ways)
        else:
            tree[parent] = (mxLength, ways)
        return
    mid = (start + end) // 2
    if element <= mid:
        update(start, mid, 2 * parent + 1, element, mxLength, ways, tree)
    else:
        update(mid + 1, end, 2 * parent + 2, element, mxLength, ways, tree)
    tree[parent] = chooseBest(tree[2 * parent + 1], tree[2 * parent + 2])
 
def maxLen(start, end, qstart, qend, parent, tree):
      # Given the range qstart to qend, return the pair with the longest maximum length.
    if start > qend or end < qstart:
        return (0, 0)
    if start >= qstart and end <= qend:
        return tree[parent]
    mid = (start + end) // 2
    left = maxLen(start, mid, qstart, qend, 2 * parent + 1, tree)
    right = maxLen(mid + 1, end, qstart, qend, 2 * parent + 2, tree)
    return chooseBest(left, right)
 
def findNumberOfLIS(nums):
      # Given an array, find the number of longest increasing subsequences.
    n = len(nums)
    mx = RANKER(nums)
    tree = [(0, 0)] * (4 * mx + 5)
    for i in range(n):
          # initialize the max length and ways for this element
        mxLen = 1
        ways = 1
        if nums[i] > 0: # if nums[i] is not the first element
            info = maxLen(0, mx, 0, nums[i] - 1, 0, tree)
            if info[0] + 1 > mxLen:
                mxLen = info[0] + 1
                ways = info[1]
        update(0, mx, 0, nums[i], mxLen, ways, tree)
    return tree[0][1]
 
# Example usage
arr = [1, 3, 5, 4, 7]
print(findNumberOfLIS(arr))  # output: 2


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
class LIS {
    public static int Ranker(int[] nums) {
        int n = nums.Length;
        int[] temp = nums.ToArray();
        Array.Sort(temp);
        Dictionary<int, int> rank = new Dictionary<int, int>();
        int mx = 0;
        for (int i = 0; i < n; i++) {
            if (!rank.ContainsKey(temp[i])) {
                rank[temp[i]] = mx;
                mx++;
            }
        }
        for (int i = 0; i < n; i++) {
            nums[i] = rank[nums[i]];
        }
        return mx;
    }
 
    public static int[] ChooseBest(int[] left, int[] right) {
        // We will choose the longest length LIS's ways.
        int mxLen_LFT = left[0];
        int ways_LFT = left[1];
        int mxLen_RHT = right[0];
        int ways_RHT = right[1];
        if (mxLen_LFT > mxLen_RHT) {
            return new int[] { mxLen_LFT, ways_LFT };
        }
        else if (mxLen_LFT < mxLen_RHT) {
            return new int[] { mxLen_RHT, ways_RHT };
        }
        else {// same length, so we will add up the ways
            return new int[] { mxLen_LFT, ways_LFT + ways_RHT };
        }
    }
 
    public static void Update(int start, int end, int parent, int element, int mxLength, int ways, int[][] tree) {
        if (start == end) { // if same maxlength is achieved again, add ways
            if (tree[parent][0] == mxLength) {
                tree[parent][1] += ways;
            }
            else {// if achieved more length, update length and ways
                tree[parent][0] = mxLength;
                tree[parent][1] = ways;
            }
            return;
        }
        int mid = (start + end) / 2;
        if (element <= mid) {
            Update(start, mid, 2 * parent + 1, element, mxLength, ways, tree);
        }
        else {
            Update(mid + 1, end, 2 * parent + 2, element, mxLength, ways, tree);
        }
        tree[parent] = ChooseBest(tree[2 * parent + 1], tree[2 * parent + 2]);
    }
 
    public static int[] MaxLen(int start, int end, int qstart, int qend, int parent, int[][] tree) {
        if (start > qend || end < qstart) {
            return new int[] { 0, 0 };
        }
        if (start >= qstart && end <= qend) {
            return tree[parent];
        }
        int mid = (start + end) / 2;
        int[] left = MaxLen(start, mid, qstart, qend, 2 * parent + 1, tree);
        int[] right = MaxLen(mid + 1, end, qstart, qend, 2 * parent + 2, tree);
        return ChooseBest(left, right);
    }
 
    public static int FindNumberOfLIS(int[] nums) {
        int n = nums.Length;
        int mx = Ranker(nums);  // step down the array
        /*
        Console.Write("Step down array -> ");
        foreach (var c in nums) {
            Console.Write(c + " ");
        }*/
 
   int[][] tree = new int[4 * mx + 5][];
    for (int i = 0; i < tree.Length; i++) {
        tree[i] = new int[2];
    }
    for (int i = 0; i < n; i++) {
        int mxLen = 1;
        int ways = 1;
        if (nums[i] > 0) {
            int[] info = MaxLen(0, mx, 0, nums[i] - 1, 0, tree);
            if (info[0] + 1 > mxLen) {
                mxLen = info[0] + 1;
                ways = info[1];
            }
        }
        Update(0, mx, 0, nums[i], mxLen, ways, tree);
    }
    return tree[0][1];
}
 
public static void Main(string[] args) {
    int[] arr = {1, 3, 5, 4, 7};
    Console.WriteLine(FindNumberOfLIS(arr));
}
}


Javascript




function RANKER(nums) {
  const n = nums.length;
  const temp = nums.slice();
  temp.sort();
  const rank = {};
  let mx = 0;
  for (let i = 0; i < n; i++) {
    if (!(temp[i] in rank)) {
      rank[temp[i]] = mx;
      mx++;
    }
  }
  for (let i = 0; i < n; i++) {
    nums[i] = rank[nums[i]];
  }
  return mx;
}
 
function chooseBest(left, right) {
  const [mxLen_LFT, ways_LFT] = left;
  const [mxLen_RHT, ways_RHT] = right;
  if (mxLen_LFT > mxLen_RHT) {
    return [mxLen_LFT, ways_LFT];
  } else if (mxLen_LFT < mxLen_RHT) {
    return [mxLen_RHT, ways_RHT];
  } else {
    return [mxLen_LFT, ways_LFT + ways_RHT];
  }
}
 
function update(start, end, parent, element, mxLength, ways, tree) {
  if (start === end) {
    if (tree[parent][0] === mxLength) {
      tree[parent] = [mxLength, tree[parent][1] + ways];
    } else {
      tree[parent] = [mxLength, ways];
    }
    return;
  }
  const mid = Math.floor((start + end) / 2);
  if (element <= mid) {
    update(start, mid, 2 * parent + 1, element, mxLength, ways, tree);
  } else {
    update(mid + 1, end, 2 * parent + 2, element, mxLength, ways, tree);
  }
  tree[parent] = chooseBest(tree[2 * parent + 1], tree[2 * parent + 2]);
}
 
function maxLen(start, end, qstart, qend, parent, tree) {
  if (start > qend || end < qstart) {
    return [0, 0];
  }
  if (start >= qstart && end <= qend) {
    return tree[parent];
  }
  const mid = Math.floor((start + end) / 2);
  const left = maxLen(start, mid, qstart, qend, 2 * parent + 1, tree);
  const right = maxLen(mid + 1, end, qstart, qend, 2 * parent + 2, tree);
  return chooseBest(left, right);
}
 
function findNumberOfLIS(nums) {
  const n = nums.length;
  const mx = RANKER(nums);
  const tree = Array(4 * mx + 5).fill([0, 0]);
  for (let i = 0; i < n; i++) {
    let mxLen = 1;
    let ways = 1;
    if (nums[i] > 0) {
      const info = maxLen(0, mx, 0, nums[i] - 1, 0, tree);
      if (info[0] + 1 > mxLen) {
        mxLen = info[0] + 1;
        ways = info[1];
      }
    }
    update(0, mx, 0, nums[i], mxLen, ways, tree);
  }
  return tree[0][1];
}
 
// Example usage
const arr = [1, 3, 5, 4, 7]
console.log(findNumberOfLIS(arr))  // output: 2


Output

2

Time Complexity: O(NlogN), logN query for N elements
Auxiliary Space: O(N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads