Given an array arr[] containing n integers. The problem is to count number of increasing subsequences in the array of size k.
Examples:
Input : arr[] = {2, 6, 4, 5, 7}, k = 3 Output : 5 The subsequences of size '3' are: {2, 6, 7}, {2, 4, 5}, {2, 4, 7}, {2, 5, 7} and {4, 5, 7}. Input : arr[] = {12, 8, 11, 13, 10, 15, 14, 16, 20}, k = 4 Output : 39
Approach: The idea is to use Dynamic Programming by define 2D matrix, say dp[][]. dp[i][j] stores the count of increasing subsequences of size i ending with element arr[j]. So dp[i][j] can be defined as:
dp[i][j] = 1, where i = 1 and 1 <= j <= n
dp[i][j] = sum(dp[i-1][j]), where 1 < i <= k, i <= j <= n and arr[m] < arr[j] for (i-1) <= m < j.
Below is the implementation of above approach:
C++
// C++ implementation to count number of // increasing subsequences of size k #include <bits/stdc++.h> using namespace std; // function to count number of increasing // subsequences of size k int numOfIncSubseqOfSizeK( int arr[], int n, int k) { int dp[k][n], sum = 0; memset (dp, 0, sizeof (dp)); // count of increasing subsequences of size 1 // ending at each arr[i] for ( int i = 0; i < n; i++) dp[0][i] = 1; // building up the matrix dp[][] // Here 'l' signifies the size of // increasing subsequence of size (l+1). for ( int l = 1; l < k; l++) { // for each increasing subsequence of size 'l' // ending with element arr[i] for ( int i = l; i < n; i++) { // count of increasing subsequences of size 'l' // ending with element arr[i] dp[l][i] = 0; for ( int j = l - 1; j < i; j++) { if (arr[j] < arr[i]) dp[l][i] += dp[l - 1][j]; } } } // sum up the count of increasing subsequences of // size 'k' ending at each element arr[i] for ( int i = k - 1; i < n; i++) sum += dp[k - 1][i]; // required number of increasing // subsequences of size k return sum; } // Driver program to test above int main() { int arr[] = { 12, 8, 11, 13, 10, 15, 14, 16, 20 }; int n = sizeof (arr) / sizeof (arr[0]); int k = 4; cout << "Number of Increasing Subsequences of size " << k << " = " << numOfIncSubseqOfSizeK(arr, n, k); return 0; } |
Java
//Java implementation to count number of // increasing subsequences of size k class GFG { // function to count number of increasing // subsequences of size k static int numOfIncSubseqOfSizeK( int arr[], int n, int k) { int dp[][] = new int [k][n], sum = 0 ; // count of increasing subsequences of size 1 // ending at each arr[i] for ( int i = 0 ; i < n; i++) { dp[ 0 ][i] = 1 ; } // building up the matrix dp[][] // Here 'l' signifies the size of // increasing subsequence of size (l+1). for ( int l = 1 ; l < k; l++) { // for each increasing subsequence of size 'l' // ending with element arr[i] for ( int i = l; i < n; i++) { // count of increasing subsequences of size 'l' // ending with element arr[i] dp[l][i] = 0 ; for ( int j = l - 1 ; j < i; j++) { if (arr[j] < arr[i]) { dp[l][i] += dp[l - 1 ][j]; } } } } // sum up the count of increasing subsequences of // size 'k' ending at each element arr[i] for ( int i = k - 1 ; i < n; i++) { sum += dp[k - 1 ][i]; } // required number of increasing // subsequences of size k return sum; } // Driver program to test above public static void main(String[] args) { int arr[] = { 12 , 8 , 11 , 13 , 10 , 15 , 14 , 16 , 20 }; int n = arr.length; int k = 4 ; System.out.print( "Number of Increasing Subsequences of size " + k + " = " + numOfIncSubseqOfSizeK(arr, n, k)); } } // This code is contributed by 29AjayKumar |
Python3
# Python3 implementation to count number # of increasing subsequences of size k import math as mt # function to count number of increasing # subsequences of size k def numOfIncSubseqOfSizeK(arr, n, k): dp = [[ 0 for i in range (n)] for i in range (k)] # count of increasing subsequences # of size 1 ending at each arr[i] for i in range (n): dp[ 0 ][i] = 1 # building up the matrix dp[][] # Here 'l' signifies the size of # increasing subsequence of size (l+1). for l in range ( 1 , k): # for each increasing subsequence of # size 'l' ending with element arr[i] for i in range (l, n): # count of increasing subsequences of # size 'l' ending with element arr[i] dp[l][i] = 0 for j in range (l - 1 , i): if (arr[j] < arr[i]): dp[l][i] + = dp[l - 1 ][j] # Sum up the count of increasing subsequences # of size 'k' ending at each element arr[i] Sum = 0 for i in range (k - 1 , n): Sum + = dp[k - 1 ][i] # required number of increasing # subsequences of size k return Sum # Driver Code arr = [ 12 , 8 , 11 , 13 , 10 , 15 , 14 , 16 , 20 ] n = len (arr) k = 4 print ( "Number of Increasing Subsequences of size" , k, "=" , numOfIncSubseqOfSizeK(arr, n, k)) # This code is contributed by # Mohit kumar 29 |
C#
// C# implementation to count number of // increasing subsequences of size k using System; public class GFG { // function to count number of increasing // subsequences of size k static int numOfIncSubseqOfSizeK( int []arr, int n, int k) { int [,]dp = new int [k,n]; int sum = 0; // count of increasing subsequences of size 1 // ending at each arr[i] for ( int i = 0; i < n; i++) { dp[0,i] = 1; } // building up the matrix dp[,] // Here 'l' signifies the size of // increasing subsequence of size (l+1). for ( int l = 1; l < k; l++) { // for each increasing subsequence of size 'l' // ending with element arr[i] for ( int i = l; i < n; i++) { // count of increasing subsequences of size 'l' // ending with element arr[i] dp[l,i] = 0; for ( int j = l - 1; j < i; j++) { if (arr[j] < arr[i]) { dp[l,i] += dp[l - 1,j]; } } } } // sum up the count of increasing subsequences of // size 'k' ending at each element arr[i] for ( int i = k - 1; i < n; i++) { sum += dp[k - 1,i]; } // required number of increasing // subsequences of size k return sum; } // Driver program to test above public static void Main() { int []arr = {12, 8, 11, 13, 10, 15, 14, 16, 20}; int n = arr.Length; int k = 4; Console.Write( "Number of Increasing Subsequences of size " + k + " = " + numOfIncSubseqOfSizeK(arr, n, k)); } } // This code is contributed by 29AjayKumar |
PHP
<?php // PHP implementation to count // number of increasing // subsequences of size k // function to count number // of increasing subsequences // of size k function numOfIncSubseqOfSizeK( $arr , $n , $k ) { $dp = array ( array ()); $sum = 0; $dp = array_fill (0, $n + 1, false); // count of increasing // subsequences of size 1 // ending at each arr[i] for ( $i = 0; $i < $n ; $i ++) $dp [0][ $i ] = 1; // building up the matrix // dp[][]. Here 'l' signifies // the size of increasing // subsequence of size (l+1). for ( $l = 1; $l < $k ; $l ++) { // for each increasing // subsequence of size 'l' // ending with element arr[i] for ( $i = $l ; $i < $n ; $i ++) { // count of increasing // subsequences of size 'l' // ending with element arr[i] $dp [ $l ][ $i ] = 0; for ( $j = $l - 1; $j < $i ; $j ++) { if ( $arr [ $j ] < $arr [ $i ]) $dp [ $l ][ $i ] += $dp [ $l - 1][ $j ]; } } } // sum up the count of increasing // subsequences of size 'k' ending // at each element arr[i] for ( $i = $k - 1; $i < $n ; $i ++) $sum += $dp [ $k - 1][ $i ]; // required number of increasing // subsequences of size k return $sum ; } // Driver Code $arr = array (12, 8, 11, 13, 10, 15, 14, 16, 20); $n = sizeof( $arr ); $k = 4; echo "Number of Increasing " . "Subsequences of size " , $k , " = " , numOfIncSubseqOfSizeK( $arr , $n , $k ); // This code is contributed // by akt_mit ?> |
Javascript
<script> // JavaScript implementation to count number of // increasing subsequences of size k // function to count number of increasing // subsequences of size k function numOfIncSubseqOfSizeK(arr, n, k) { let dp = new Array(k), sum = 0; // Loop to create 2D array using 1D array for (let i = 0; i < dp.length; i++) { dp[i] = new Array(2); } // count of increasing subsequences of size 1 // ending at each arr[i] for (let i = 0; i < n; i++) { dp[0][i] = 1; } // building up the matrix dp[][] // Here 'l' signifies the size of // increasing subsequence of size (l+1). for (let l = 1; l < k; l++) { // for each increasing subsequence of size 'l' // ending with element arr[i] for (let i = l; i < n; i++) { // count of increasing subsequences of size 'l' // ending with element arr[i] dp[l][i] = 0; for (let j = l - 1; j < i; j++) { if (arr[j] < arr[i]) { dp[l][i] += dp[l - 1][j]; } } } } // sum up the count of increasing subsequences of // size 'k' ending at each element arr[i] for (let i = k - 1; i < n; i++) { sum += dp[k - 1][i]; } // required number of increasing // subsequences of size k return sum; } // Driver code let arr = [12, 8, 11, 13, 10, 15, 14, 16, 20]; let n = arr.length; let k = 4; document.write( "Number of Increasing Subsequences of size " + k + " = " + numOfIncSubseqOfSizeK(arr, n, k)); </script> |
Number of Increasing Subsequences of size 4 = 39
Time Complexity: O(kn2).
Auxiliary Space: O(kn).
Segment Tree Approach
For every element arr[i], we need to search for all arr[i]-1 as these are the elements that can be appended to arr[i] to make increasing subsequence. This is very much similar to COUNT LONGEST INCREASING SUBSEQUENCES. We use a vector of size K for each node in segment Tree signifying the length of LIS of size K ending at node.
Stepping down the array to smaller numbers with same ordering will reduce the space complexity as well.
If arr[i] has vector K={1,3,2}, signifies there is one K=1 length LIS ending at arr[i]
three K=2 length LIS ending at arr[i]
two K=3 length LIS ending at arr[i]
If arr[j] is greater than arr[i], then arr[j] can appended after arr[i]. So the vector of arr[j] becomes {1,1,3}.
The K=1 remains the same since every element itself is a single length(K=1) subsequence.
We will take subsequences of length K=1 from arr[i] in the K=2 of arr[j] Since all the K=1 increasing subsequences of arr[i] becomes K=2 length increasing subsequences when arr[j] is added to arr[i].
Similarly all the K=2 length subsequences of arr[i] becomes K=3 length subsequences for arr[j] as arr[j] gets appended to K=2 subsequences of arr[i]. We are not adding here, because we are calculating ways, not length.
Simply saying vec_j[K]=vec_i[K-1], where K>1
Below is the implementation of above approach:
C++
#include <bits/stdc++.h> using namespace std; vector<vector< long long >>tree; /* vector<long long> represents the number of ways LIS of size K ending at node can be formed */ int RANKER(vector< int >& arr) { int n = arr.size(); vector< int > temp = arr; sort(temp.begin(), temp.end()); unordered_map< int , int > mpp; int mx = 0; for ( int i = 0; i < n; i++) { if (mpp.find(temp[i]) == mpp.end()) { mpp[temp[i]] = mx; mx++; } } for ( int i = 0; i < n; i++) { arr[i] = mpp[arr[i]]; } return mx; } vector< long long > summation(vector< long long >& left, vector< long long >& right, int k) { // ADD WAYS, REMEMBER NO NEED TO TAKE MAX, WE ARE FINDING WAYS, NOT LENGTH. // So each K will contribute to final answer vector< long long > res(k + 1, 0); for ( int i = 1; i <= k; i++) { res[i] = left[i] + right[i]; } return res; } vector< long long > query( int start, int end, int parent, int qstart, int qend, int k) { if (end < qstart || qend < start) { return vector< long long >(k + 1, 0); } if (qstart <= start && qend >= end) { return tree[parent]; } int mid = (start + end) / 2; vector< long long > left = query(start, mid, 2 * parent + 1, qstart, qend, k); vector< long long > right = query(mid + 1, end, 2 * parent + 2, qstart, qend, k); return summation(left, right, k); } void update( int start, int end, int parent, int index, vector< long long >& updateThis, int k) { if (index < start || index > end) { return ; } if (start == end) { tree[parent] = summation(updateThis, tree[parent], k); return ; } int mid = (start + end) / 2; if (index > mid) { update(mid + 1, end, 2 * parent + 2, index, updateThis, k); } else { update(start, mid, 2 * parent + 1, index, updateThis, k); } vector< long long > left = tree[2 * parent + 1]; vector< long long > right = tree[2 * parent + 2]; tree[parent] = summation(left, right, k); return ; } int numOfIncSubseqOfSizeK(vector< int >& arr, int K) { int n = arr.size(); int mx = RANKER(arr); tree.resize(4 * mx + 1, vector< long long >(K + 1, 0)); for ( int i = 0; i < n; i++) { vector< long long > Kj(K + 1, 0); // K length ways Kj[1] = 1; // K=1 is element itself if (arr[i] > 0) { // arr[0] cannot be queried, since its the lowest /* Querying the longest LIS K array where arr[i] can append to*/ vector< long long > Ki = query(0, mx, 0, 0, arr[i] - 1, K); for ( int k = 2; k <= K; k++) { // As explained before Kj[k] = Ki[k - 1]; } } update(0, mx, 0, arr[i], Kj, K); // update Kj array for arr[i] } return tree[0][K]; // answer is at kth index of root's K array } int main() { vector< int > arr = { 12, 8, 11, 13, 10, 15, 14, 16, 20 }; int k = 4; cout << "Number of Increasing Subsequences of size " << k << " = " << numOfIncSubseqOfSizeK(arr, k); return 0; } // Code by RainX (ABHIJIT ROY, NIT AGARTALA) |
Python3
from typing import List , Dict tree = [] def RANKER(arr: List [ int ]) - > int : n = len (arr) temp = arr.copy() temp.sort() mpp = {} mx = 0 for i in range (n): if temp[i] not in mpp: mpp[temp[i]] = mx mx + = 1 for i in range (n): arr[i] = mpp[arr[i]] return mx def summation(left: List [ int ], right: List [ int ], k: int ) - > List [ int ]: # ADD WAYS, REMEMBER NO NEED TO TAKE MAX, WE ARE FINDING WAYS, NOT LENGTH. # So each K will contribute to final answer res = [ 0 ] * (k + 1 ) for i in range ( 1 , k + 1 ): res[i] = left[i] + right[i] return res def query(start: int , end: int , parent: int , qstart: int , qend: int , k: int ) - > List [ int ]: if end < qstart or qend < start: return [ 0 ] * (k + 1 ) if qstart < = start and qend > = end: return tree[parent] mid = (start + end) / / 2 left = query(start, mid, 2 * parent + 1 , qstart, qend, k) right = query(mid + 1 , end, 2 * parent + 2 , qstart, qend, k) return summation(left, right, k) def update(start: int , end: int , parent: int , index: int , updateThis: List [ int ], k: int ) - > None : if index < start or index > end: return if start = = end: tree[parent] = summation(updateThis, tree[parent], k) return mid = (start + end) / / 2 if index > mid: update(mid + 1 , end, 2 * parent + 2 , index, updateThis, k) else : update(start, mid, 2 * parent + 1 , index, updateThis, k) left = tree[ 2 * parent + 1 ] right = tree[ 2 * parent + 2 ] tree[parent] = summation(left, right, k) return def numOfIncSubseqOfSizeK(arr: List [ int ], K: int ) - > int : n = len (arr) mx = RANKER(arr) global tree tree = [[ 0 ] * (K + 1 ) for _ in range ( 4 * mx + 1 )] for i in range (n): # K length ways Kj = [ 0 ] * (K + 1 ) # K=1 is element itself Kj[ 1 ] = 1 # arr[0] cannot be queried, since its the lowest if arr[i] > 0 : # Querying the longest LIS K array where arr[i] can append to Ki = query( 0 , mx, 0 , 0 , arr[i] - 1 , K) # As explained before for k in range ( 2 , K + 1 ): Kj[k] = Ki[k - 1 ] # update Kj array for arr[i] update( 0 , mx, 0 , arr[i], Kj, K) # answer is at kth index of root's K array return tree[ 0 ][K] if __name__ = = '__main__' : arr = [ 12 , 8 , 11 , 13 , 10 , 15 , 14 , 16 , 20 ] k = 4 print ( "Number of Increasing Subsequences of size" , k, "=" , numOfIncSubseqOfSizeK(arr, k)) # This code is contributed by shivhack999 |
Javascript
let tree = []; /* array of arrays, where each inner array represents the number of ways LIS of size K ending at node can be formed */ function RANKER(arr) { let n = arr.length; let temp = [...arr]; temp.sort((a, b) => a - b); let mpp = new Map(); let mx = 0; for (let i = 0; i < n; i++) { if (!mpp.has(temp[i])) { mpp.set(temp[i], mx); mx++; } } for (let i = 0; i < n; i++) { arr[i] = mpp.get(arr[i]); } return mx; } function summation(left, right, k) { // ADD WAYS, REMEMBER NO NEED TO TAKE MAX, WE ARE FINDING WAYS, NOT LENGTH. // So each K will contribute to final answer let res = new Array(k + 1).fill(0); for (let i = 1; i <= k; i++) { res[i] = left[i] + right[i]; } return res; } function query(start, end, parent, qstart, qend, k) { if (end < qstart || qend < start) { return new Array(k + 1).fill(0); } if (qstart <= start && qend >= end) { return tree[parent]; } let mid = Math.floor((start + end) / 2); let left = query(start, mid, 2 * parent + 1, qstart, qend, k); let right = query(mid + 1, end, 2 * parent + 2, qstart, qend, k); return summation(left, right, k); } function update(start, end, parent, index, updateThis, k) { if (index < start || index > end) { return ; } if (start === end) { tree[parent] = summation(updateThis, tree[parent], k); return ; } let mid = Math.floor((start + end) / 2); if (index > mid) { update(mid + 1, end, 2 * parent + 2, index, updateThis, k); } else { update(start, mid, 2 * parent + 1, index, updateThis, k); } let left = tree[2 * parent + 1]; let right = tree[2 * parent + 2]; tree[parent] = summation(left, right, k); return ; } function numOfIncSubseqOfSizeK(arr, K) { const n = arr.length; const mx = RANKER(arr); tree = new Array(4 * mx + 1).fill().map(() => new Array(K + 1).fill(0)); for (let i = 0; i < n; i++) { const Kj = new Array(K + 1).fill(0); Kj[1] = 1; if (arr[i] > 0) { const Ki = query(0, mx, 0, 0, arr[i] - 1, K); for (let k = 2; k <= K; k++) { Kj[k] = Ki[k - 1]; } } update(0, mx, 0, arr[i], Kj, K); } return tree[0][K]; } const arr = [12, 8, 11, 13, 10, 15, 14, 16, 20]; const k = 4; console.log(`Number of Increasing Subsequences of size ${k} = ${numOfIncSubseqOfSizeK(arr, k)}`); |
Number of Increasing Subsequences of size 4 = 39
Time Complexity: O(n*K*logn). For each index, we need to do query(logn) and update in K array(k)
Auxiliary Space: O(kn).
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!