Wednesday, July 3, 2024
HomeData ModellingData Structure & AlgorithmLongest subsequence whose sum is divisible by a given number

Longest subsequence whose sum is divisible by a given number

Given an array arr[] and an integer M, the task is to find the length of the longest subsequence whose sum is divisible by M. If there is no such sub-sequence then print 0
Examples: 
 

Input: arr[] = {3, 2, 2, 1}, M = 3 
Output:
Longest sub-sequence whose sum is 
divisible by 3 is {3, 2, 1}
Input: arr[] = {2, 2}, M = 3 
Output:
 

 

Approach: A simple way to solve this will be to generate all the possible sub-sequences and then find the largest among them divisible whose sum is divisible by M. However, for smaller values of M, a dynamic programming based approach can be used. 
Let’s look at the recurrence relation first. 
 

dp[i][curr_mod] = max(dp[i + 1][curr_mod], dp[i + 1][(curr_mod + arr[i]) % m] + 1) 
 

Let’s understand the states of DP now. Here, dp[i][curr_mod] stores the longest subsequence of subarray arr[i…N-1] such that the sum of this subsequence and curr_mod is divisible by M. At each step, either index i can be chosen updating curr_mod or it can be ignored.
Also, note that only SUM % m needs to be stored instead of the entire sum as this information is sufficient to complete the states of DP.
Below is the implementation of the above approach: 
 

C++




// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
#define maxN 20
#define maxM 64
 
// To store the states of DP
int dp[maxN][maxM];
bool v[maxN][maxM];
 
// Function to return the length
// of the longest subsequence
// whose sum is divisible by m
int findLen(int* arr, int i, int curr,
            int n, int m)
{
    // Base case
    if (i == n) {
        if (!curr)
            return 0;
        else
            return -1;
    }
 
    // If the state has been solved before
    // return the value of the state
    if (v[i][curr])
        return dp[i][curr];
 
    // Setting the state as solved
    v[i][curr] = 1;
 
    // Recurrence relation
    int l = findLen(arr, i + 1, curr, n, m);
    int r = findLen(arr, i + 1,
                    (curr + arr[i]) % m, n, m);
    dp[i][curr] = l;
    if (r != -1)
        dp[i][curr] = max(dp[i][curr], r + 1);
    return dp[i][curr];
}
 
// Driver code
int main()
{
    int arr[] = { 3, 2, 2, 1 };
    int n = sizeof(arr) / sizeof(int);
    int m = 3;
 
    cout << findLen(arr, 0, 0, n, m);
 
    return 0;
}


Java




// Java implementation of the approach
class GFG
{
 
static int maxN = 20;
static int maxM = 64;
 
// To store the states of DP
static int [][]dp = new int[maxN][maxM];
static boolean [][]v = new boolean[maxN][maxM];
 
// Function to return the length
// of the longest subsequence
// whose sum is divisible by m
static int findLen(int[] arr, int i,
                   int curr, int n, int m)
{
    // Base case
    if (i == n)
    {
        if (curr == 0)
            return 0;
        else
            return -1;
    }
 
    // If the state has been solved before
    // return the value of the state
    if (v[i][curr])
        return dp[i][curr];
 
    // Setting the state as solved
    v[i][curr] = true;
 
    // Recurrence relation
    int l = findLen(arr, i + 1, curr, n, m);
    int r = findLen(arr, i + 1,
                   (curr + arr[i]) % m, n, m);
    dp[i][curr] = l;
    if (r != -1)
        dp[i][curr] = Math.max(dp[i][curr], r + 1);
    return dp[i][curr];
}
 
// Driver code
public static void main(String []args)
{
    int arr[] = { 3, 2, 2, 1 };
    int n = arr.length;
    int m = 3;
 
    System.out.println(findLen(arr, 0, 0, n, m));
}
}
 
// This code is contributed by 29AjayKumar


Python3




# Python3 implementation of the approach
import numpy as np
 
maxN = 20
maxM = 64
 
# To store the states of DP
dp = np.zeros((maxN, maxM));
v = np.zeros((maxN, maxM));
 
# Function to return the length
# of the longest subsequence
# whose sum is divisible by m
def findLen(arr, i, curr, n, m) :
     
    # Base case
    if (i == n) :
        if (not curr) :
            return 0;
        else :
            return -1;
 
    # If the state has been solved before
    # return the value of the state
    if (v[i][curr]) :
        return dp[i][curr];
 
    # Setting the state as solved
    v[i][curr] = 1;
 
    # Recurrence relation
    l = findLen(arr, i + 1, curr, n, m);
    r = findLen(arr, i + 1,
               (curr + arr[i]) % m, n, m);
     
    dp[i][curr] = l;
    if (r != -1) :
        dp[i][curr] = max(dp[i][curr], r + 1);
         
    return dp[i][curr];
 
# Driver code
if __name__ == "__main__" :
 
    arr = [ 3, 2, 2, 1 ];
    n = len(arr);
    m = 3;
 
    print(findLen(arr, 0, 0, n, m));
 
# This code is contributed by AnkitRai


C#




// C# implementation of the approach
using System;
                     
class GFG
{
     
static int maxN = 20;
static int maxM = 64;
 
// To store the states of DP
static int [,]dp = new int[maxN, maxM];
static Boolean [,]v = new Boolean[maxN, maxM];
 
// Function to return the length
// of the longest subsequence
// whose sum is divisible by m
static int findLen(int[] arr, int i,
                   int curr, int n, int m)
{
    // Base case
    if (i == n)
    {
        if (curr == 0)
            return 0;
        else
            return -1;
    }
 
    // If the state has been solved before
    // return the value of the state
    if (v[i, curr])
        return dp[i, curr];
 
    // Setting the state as solved
    v[i, curr] = true;
 
    // Recurrence relation
    int l = findLen(arr, i + 1, curr, n, m);
    int r = findLen(arr, i + 1,
                   (curr + arr[i]) % m, n, m);
    dp[i, curr] = l;
    if (r != -1)
        dp[i, curr] = Math.Max(dp[i, curr], r + 1);
    return dp[i, curr];
}
 
// Driver code
public static void Main(String []args)
{
    int []arr = { 3, 2, 2, 1 };
    int n = arr.Length;
    int m = 3;
 
    Console.WriteLine(findLen(arr, 0, 0, n, m));
}
}
 
// This code is contributed by 29AjayKumar


Javascript




<script>
 
// Javascript implementation of the approach
var maxN = 20
var maxM = 64
 
// To store the states of DP
var dp = Array.from(Array(maxN), ()=> Array(maxM).fill(0));
var v = Array.from(Array(maxN), ()=> Array(maxM).fill(false));
 
// Function to return the length
// of the longest subsequence
// whose sum is divisible by m
function findLen(arr, i, curr, n, m)
{
    // Base case
    if (i == n) {
        if (!curr)
            return 0;
        else
            return -1;
    }
 
    // If the state has been solved before
    // return the value of the state
    if (v[i][curr])
        return dp[i][curr];
 
    // Setting the state as solved
    v[i][curr] = 1;
 
    // Recurrence relation
    var l = findLen(arr, i + 1, curr, n, m);
    var r = findLen(arr, i + 1, (curr + arr[i]) % m, n, m);
    dp[i][curr] = l;
    if (r != -1)
        dp[i][curr] = Math.max(dp[i][curr], r + 1);
    return dp[i][curr];
}
 
// Driver code
var arr = [3, 2, 2, 1];
var n = arr.length;
var m = 3;
document.write( findLen(arr, 0, 0, n, m));
 
</script>


Output

3







Time Complexity: O(N * M)
Auxiliary Space: O(N * M). 
 

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 + memoization(top-down) because memoization method needs extra stack space of recursion calls.

Steps to solve this problem :

  • Create a DP to store the solution of the subproblems.
  • Initialize the DP with base cases by initializing the values of DP with 0 and -1.
  • Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in DP
  • Return the final solution stored in dp[0][0].

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
#define maxN 20
#define maxM 64
 
// Function to return the length of the longest subsequence
// whose sum is divisible by m
int findLen(int* arr, int n, int m)
{
    // To store the states of DP
    int dp[n + 1][maxM];
 
    // Base case
    for (int curr = 0; curr < m; ++curr) {
        if (curr == 0)
            dp[n][curr] = 0;
        else
            dp[n][curr] = -1;
    }
 
    // Tabulation
    for (int i = n - 1; i >= 0; --i) {
        for (int curr = 0; curr < m; ++curr) {
            // Recurrence relation
            int l = dp[i + 1][curr];
            int r = dp[i + 1][(curr + arr[i]) % m];
            dp[i][curr] = l;
            if (r != -1)
                dp[i][curr] = max(dp[i][curr], r + 1);
        }
    }
 
    if (dp[0][0] == -1)
        return 0;
    else
        return dp[0][0];
}
 
// Driver code
int main()
{
    int arr[] = { 3, 2, 2, 1 };
    int n = sizeof(arr) / sizeof(int);
    int m = 3;
 
      // Function call
    cout << findLen(arr, n, m);
 
    return 0;
}
// -- by bhardwajji


Java




import java.util.Arrays;
 
public class Main {
    static final int maxN = 20;
    static final int maxM = 64;
 
    // Function to return the length of the longest
    // subsequence whose sum is divisible by m
    static int findLen(int[] arr, int n, int m)
    {
        // To store the states of DP
        int[][] dp = new int[n + 1][maxM];
 
        // Base case
        for (int curr = 0; curr < m; ++curr) {
            if (curr == 0)
                dp[n][curr] = 0;
            else
                dp[n][curr] = -1;
        }
 
        // Tabulation
        for (int i = n - 1; i >= 0; --i) {
            for (int curr = 0; curr < m; ++curr) {
                // Recurrence relation
                int l = dp[i + 1][curr];
                int r = dp[i + 1][(curr + arr[i]) % m];
                dp[i][curr] = l;
                if (r != -1)
                    dp[i][curr]
                        = Math.max(dp[i][curr], r + 1);
            }
        }
 
        if (dp[0][0] == -1)
            return 0;
        else
            return dp[0][0];
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int[] arr = { 3, 2, 2, 1 };
        int n = arr.length;
        int m = 3;
 
        // Function call
        System.out.println(findLen(arr, n, m));
    }
}


Python




def find_len(arr, n, m):
    # Define the maximum values for maxN and maxM
    maxN = 20
    maxM = 64
 
    # To store the states of DP
    dp = [[0 for _ in range(maxM)] for _ in range(n + 1)]
 
    # Base case
    for curr in range(m):
        if curr == 0:
            dp[n][curr] = 0
        else:
            dp[n][curr] = -1
 
    # Tabulation
    for i in range(n - 1, -1, -1):
        for curr in range(m):
            # Recurrence relation
            l = dp[i + 1][curr]
            r = dp[i + 1][(curr + arr[i]) % m]
            dp[i][curr] = l
            if r != -1:
                dp[i][curr] = max(dp[i][curr], r + 1)
 
    if dp[0][0] == -1:
        return 0
    else:
        return dp[0][0]
 
 
if __name__ == "__main__":
    arr = [3, 2, 2, 1]
    n = len(arr)
    m = 3
 
    # Function call
    print(find_len(arr, n, m))


C#




using System;
 
class GFG {
    const int maxN = 20;
    const int maxM = 64;
 
    // Function to return the length of the longest
    // subsequence whose sum is divisible by m
    static int FindLen(int[] arr, int n, int m)
    {
        // To store the states of DP
        int[, ] dp = new int[n + 1, maxM];
 
        // Base case
        for (int curr = 0; curr < m; ++curr) {
            if (curr == 0)
                dp[n, curr] = 0;
            else
                dp[n, curr] = -1;
        }
 
        // Tabulation
        for (int i = n - 1; i >= 0; --i) {
            for (int curr = 0; curr < m; ++curr) {
                // Recurrence relation
                int l = dp[i + 1, curr];
                int r = dp[i + 1, (curr + arr[i]) % m];
                dp[i, curr] = l;
                if (r != -1)
                    dp[i, curr]
                        = Math.Max(dp[i, curr], r + 1);
            }
        }
 
        if (dp[0, 0] == -1)
            return 0;
        else
            return dp[0, 0];
    }
 
    // Driver code
    static void Main(string[] args)
    {
        int[] arr = { 3, 2, 2, 1 };
        int n = arr.Length;
        int m = 3;
 
        // Function call
        Console.WriteLine(FindLen(arr, n, m));
    }
}


Javascript




// Function to return the length of the longest subsequence
// whose sum is divisible by m
function findLen(arr, n, m) {
    // To store the states of DP
    const dp = new Array(n + 1);
    for (let i = 0; i <= n; i++) {
        dp[i] = new Array(m);
    }
 
    // Base case
    for (let curr = 0; curr < m; curr++) {
        if (curr === 0) {
            dp[n][curr] = 0;
        } else {
            dp[n][curr] = -1;
        }
    }
 
    // Tabulation
    for (let i = n - 1; i >= 0; i--) {
        for (let curr = 0; curr < m; curr++) {
            // Recurrence relation
            let l = dp[i + 1][curr];
            let r = dp[i + 1][(curr + arr[i]) % m];
            dp[i][curr] = l;
            if (r !== -1) {
                dp[i][curr] = Math.max(dp[i][curr], r + 1);
            }
        }
    }
 
    if (dp[0][0] === -1) {
        return 0;
    } else {
        return dp[0][0];
    }
}
 
// Driver code
const arr = [3, 2, 2, 1];
const n = arr.length;
const m = 3;
 
// Function call
console.log(findLen(arr, n, m));


Output

3







Time Complexity: O(N * M)
Auxiliary Space: O(N * M). 

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

Nango Kalahttps://www.kala.co.za
Experienced Support Engineer with a demonstrated history of working in the information technology and services industry. Skilled in Microsoft Excel, Customer Service, Microsoft Word, Technical Support, and Microsoft Office. Strong information technology professional with a Microsoft Certificate Solutions Expert (Privet Cloud) focused in Information Technology from Broadband Collage Of Technology.
RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments