Shortest Subsequence with sum exactly K
Last Updated :
12 Apr, 2023
Given an array Arr[] of size N and an integer K, the task is to find the length of the shortest subsequence having sum exactly K.
Examples:
Input: N = 5, K = 4, Arr[] = {1, 2, 2, 3, 4}
Output: 1
Explanation: Here, one can choose the last month and can get 4 working hours.
Input: N = 3, K = 2, Arr[] = {1, 3, 5}
Output: -1
Explanation: Here, we can not get exactly 2 hours of work from any month.
Naive Approach: One of the most basic ways of solving the above problem is to generate all the subsets using Recursion and choose the subset with the smallest size which sums exactly K.
Time complexity: O (N * 2N).
Auxiliary Space: O(1)
Efficient Approach: The above problem can be solved in dynamic programming efficiently in the following way.
On each index there are two choices: either to include the element in the subsequence or not. To efficiently calculate this, use a two dimensional dp[][] array where dp[i][j] stores the minimum length of subsequence with sum j up to ith index.
Follow the below steps to implement the approach:
- Iterate from the start of the array.
- For each element there are two choices: either pick the element or not.
- If the value of the ith element is greater than the required sum (say X) to have subsequence sum K then it cannot be included.
- Otherwise do the following:
- Pick the ith element, update the required sum as (X-Arr[i]) and recursively do the same for the next index in step 5.
- Don’t insert the element in subsequence and call recursively for the next element.
- Store the minimum between these two in the dp[][] array.
- In each recursive call:
- If the required sum is 0 store the length of subsequence in dp[][] array.
- If it is already calculated for this same value of i and X it is already calculated then return the same.
- If not possible to achieve a subsequence sum exactly K from this state, return -1.
- The final value at dp[0][K] will denote the minimum subsequence length.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int minSize(vector<vector< int > >& dp,
int i, vector< int >& arr,
int k, int n)
{
if (k == 0)
return 0;
if (i == n)
return -1;
if (dp[i][k] != 0)
return dp[i][k];
int x, y, maxi;
maxi = INT_MAX;
x = y = maxi;
if (arr[i] <= k) {
int m = minSize(dp, i + 1, arr,
k - arr[i], n);
if (m != -1) {
x = min(x, m + 1);
}
}
int m = minSize(dp, i + 1, arr, k, n);
if (m != -1) {
y = min(y, m);
}
return (dp[i][k]
= (x == maxi and y == maxi) ? -1
: min(x, y));
}
int seqLength(vector< int >& arr, int k)
{
int n = arr.size();
vector<vector< int > > dp(n,
vector< int >(k + 1,
0));
return minSize(dp, 0, arr, k, n);
}
int main()
{
int N = 5;
int K = 4;
vector< int > arr = { 1, 2, 2, 3, 4 };
cout << seqLength(arr, K) << endl;
return 0;
}
|
Java
import java.util.*;
class GFG {
static int minSize( int [][] dp, int i, int [] arr, int k,
int n)
{
if (k == 0 )
return 0 ;
if (i == n)
return - 1 ;
if (dp[i][k] != 0 )
return dp[i][k];
int x = 0 , y = 0 , maxi = Integer.MAX_VALUE;
x = y = maxi;
if (arr[i] <= k) {
int m1 = minSize(dp, i + 1 , arr, k - arr[i], n);
if (m1 != - 1 ) {
x = Math.min(x, m1 + 1 );
}
}
int m2 = minSize(dp, i + 1 , arr, k, n);
if (m2 != - 1 ) {
y = Math.min(y, m2);
}
return (dp[i][k] = (x == maxi && y == maxi)
? - 1
: Math.min(x, y));
}
static int seqLength( int [] arr, int k)
{
int n = arr.length;
int [][] dp = new int [n][k + 1 ];
for ( int i = 0 ; i < n; i++) {
for ( int j = 0 ; j < k + 1 ; j++) {
dp[i][j] = 0 ;
}
}
return minSize(dp, 0 , arr, k, n);
}
public static void main(String args[])
{
int N = 5 ;
int K = 4 ;
int [] arr = { 1 , 2 , 2 , 3 , 4 };
System.out.print(seqLength(arr, K));
}
}
|
Python3
INT_MAX = 2147483647
def minSize(dp, i, arr, k, n):
if (k = = 0 ):
return 0
if (i = = n):
return - 1
if (dp[i][k] ! = 0 ):
return dp[i][k]
maxi = INT_MAX
x = y = maxi
if (arr[i] < = k):
m = minSize(dp, i + 1 , arr, k - arr[i], n)
if (m ! = - 1 ):
x = min (x, m + 1 )
m = minSize(dp, i + 1 , arr, k, n)
if (m ! = - 1 ):
y = min (y, m)
dp[i][k] = - 1 if (x = = maxi and y = = maxi) else min (x, y)
return dp[i][k]
def seqLength(arr, k):
n = len (arr)
dp = [[ 0 for _ in range (K + 1 )] for _ in range (n)]
return minSize(dp, 0 , arr, k, n)
if __name__ = = "__main__" :
N = 5
K = 4
arr = [ 1 , 2 , 2 , 3 , 4 ]
print (seqLength(arr, K))
|
C#
using System;
class GFG {
static int minSize( int [, ] dp, int i, int [] arr, int k,
int n)
{
if (k == 0)
return 0;
if (i == n)
return -1;
if (dp[i, k] != 0)
return dp[i, k];
int x = 0, y = 0, maxi = Int32.MaxValue;
x = y = maxi;
if (arr[i] <= k) {
int m1 = minSize(dp, i + 1, arr, k - arr[i], n);
if (m1 != -1) {
x = Math.Min(x, m1 + 1);
}
}
int m2 = minSize(dp, i + 1, arr, k, n);
if (m2 != -1) {
y = Math.Min(y, m2);
}
return (dp[i, k] = (x == maxi && y == maxi)
? -1
: Math.Min(x, y));
}
static int seqLength( int [] arr, int k)
{
int n = arr.Length;
int [, ] dp = new int [n, k + 1];
for ( int i = 0; i < n; i++) {
for ( int j = 0; j < k + 1; j++) {
dp[i, j] = 0;
}
}
return minSize(dp, 0, arr, k, n);
}
public static void Main()
{
int N = 5;
int K = 4;
int [] arr = { 1, 2, 2, 3, 4 };
Console.WriteLine(seqLength(arr, K));
}
}
|
Javascript
<script>
function minSize(dp,
i, arr, k, n)
{
if (k == 0)
return 0;
if (i == n)
return -1;
if (dp[i][k] != 0)
return dp[i][k];
let x, y, maxi;
maxi = Number.MAX_VALUE;
x = y = maxi;
if (arr[i] <= k) {
let m = minSize(dp, i + 1, arr,
k - arr[i], n);
if (m != -1) {
x = Math.min(x, m + 1);
}
}
let m = minSize(dp, i + 1, arr, k, n);
if (m != -1) {
y = Math.min(y, m);
}
return (dp[i][k]
= (x == maxi && y == maxi) ? -1
: Math.min(x, y));
}
function seqLength(arr, k) {
let n = arr.length;
let dp = new Array(n)
for (let i = 0; i < dp.length; i++) {
dp[i] = new Array(k + 1).fill(0)
}
return minSize(dp, 0, arr, k, n);
}
let N = 5;
let K = 4;
let arr = [1, 2, 2, 3, 4];
document.write(seqLength(arr, K) + '<br>' );
</script>
|
Time Complexity: O(N * K)
Auxiliary Space: O(N * K)
Efficient approach : Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memorization(top-down) because memorization method needs extra stack space of recursion calls.
Steps to solve this problem :
- Initialize a 2D vector dp of size (n+1) x (k+1) where n is the size of the input vector arr.
- Initialize the base case dp[i][0] = 0 for all i from 0 to n.
- For each element arr[i] in the input vector arr, and for each sum value j from 1 to k:
a. If arr[i] is greater than j, set dp[i][j] = dp[i-1][j].
b. Otherwise, set dp[i][j] = min(dp[i-1][j-arr[i]] + 1, dp[i-1][j]).
- Return dp[n][k] if it is less than INT_MAX, otherwise return -1.
Implementation :
C++
#include <bits/stdc++.h>
using namespace std;
int seqLength(vector< int >& arr, int k)
{
int n = arr.size();
vector<vector< int > > dp(n + 1, vector< int >(k + 1, 1e9));
for ( int i = 0; i <= n; i++)
dp[i][0] = 0;
for ( int i = 1; i <= n; i++) {
for ( int j = 1; j <= k; j++) {
if (arr[i - 1] > j) {
dp[i][j] = dp[i - 1][j];
}
else {
dp[i][j] = min(dp[i - 1][j - arr[i - 1]] + 1, dp[i - 1][j]);
}
}
}
return (dp[n][k] >= 1e9) ? -1 : dp[n][k];
}
int main()
{
int N = 5;
int K = 4;
vector< int > arr = { 1, 2, 2, 3, 4 };
cout << seqLength(arr, K) << endl;
return 0;
}
|
Java
import java.util.*;
class Main {
static int seqLength(ArrayList<Integer> arr, int k) {
int n = arr.size();
int [][] dp = new int [n + 1 ][k + 1 ];
for ( int [] row : dp)
Arrays.fill(row, 1000000000 );
for ( int i = 0 ; i <= n; i++)
dp[i][ 0 ] = 0 ;
for ( int i = 1 ; i <= n; i++) {
for ( int j = 1 ; j <= k; j++) {
if (arr.get(i - 1 ) > j) {
dp[i][j] = dp[i - 1 ][j];
}
else {
dp[i][j] = Math.min(dp[i - 1 ][j - arr.get(i - 1 )] + 1 , dp[i - 1 ][j]);
}
}
}
return (dp[n][k] >= 1000000000 ) ? - 1 : dp[n][k];
}
public static void main(String[] args) {
int N = 5 ;
int K = 4 ;
ArrayList<Integer> arr = new ArrayList<>(Arrays.asList( 1 , 2 , 2 , 3 , 4 ));
System.out.println(seqLength(arr, K));
}
}
|
Python3
def seqLength(arr, k):
n = len (arr)
dp = [[ 1e9 for j in range (k + 1 )] for i in range (n + 1 )]
for i in range (n + 1 ):
dp[i][ 0 ] = 0
for i in range ( 1 , n + 1 ):
for j in range ( 1 , k + 1 ):
if arr[i - 1 ] > j:
dp[i][j] = dp[i - 1 ][j]
else :
dp[i][j] = min (dp[i - 1 ][j - arr[i - 1 ]] + 1 , dp[i - 1 ][j])
return - 1 if dp[n][k] > = 1e9 else dp[n][k]
if __name__ = = '__main__' :
N = 5
K = 4
arr = [ 1 , 2 , 2 , 3 , 4 ]
print (seqLength(arr, K))
|
C#
using System;
using System.Collections.Generic;
public class GFG {
static int seqLength(List< int > arr, int k)
{
int n = arr.Count;
List<List< int >> dp = new List<List< int >>();
for ( int i = 0; i <= n; i++) {
dp.Add( new List< int >());
for ( int j = 0; j <= k; j++) {
dp[i].Add(1000000000);
}
}
for ( int i = 0; i <= n; i++) {
dp[i][0] = 0;
}
for ( int i = 1; i <= n; i++) {
for ( int j = 1; j <= k; j++) {
if (arr[i - 1] > j) {
dp[i][j] = dp[i - 1][j];
}
else {
dp[i][j] = Math.Min(dp[i - 1][j - arr[i - 1]] + 1, dp[i - 1][j]);
}
}
}
return (dp[n][k] >= 1000000000) ? -1 : dp[n][k];
}
public static void Main()
{
int K = 4;
List< int > arr = new List< int >() { 1, 2, 2, 3, 4 };
Console.WriteLine(seqLength(arr, K));
}
}
|
Javascript
function seqLength(arr, k) {
let n = arr.length;
let dp = new Array(n + 1).fill(0).map(() => new Array(k + 1).fill(1e9));
for (let i = 0; i <= n; i++) {
dp[i][0] = 0;
}
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= k; j++) {
if (arr[i - 1] > j) {
dp[i][j] = dp[i - 1][j];
}
else {
dp[i][j] = Math.min(dp[i - 1][j - arr[i - 1]] + 1, dp[i - 1][j]);
}
}
}
return dp[n][k] >= 1e9 ? -1 : dp[n][k];
}
let N = 5;
let K = 4;
let arr = [1, 2, 2, 3, 4];
console.log(seqLength(arr, K));
|
Output:
1
Time Complexity: O(N * K)
Auxiliary Space: O(N * K)
Share your thoughts in the comments
Please Login to comment...