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: 3
Longest sub-sequence whose sum is
divisible by 3 is {3, 2, 1}
Input: arr[] = {2, 2}, M = 3
Output: 0
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 DPint dp[maxN][maxM];bool v[maxN][maxM];// Function to return the length// of the longest subsequence// whose sum is divisible by mint 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 codeint 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 approachclass GFG{static int maxN = 20;static int maxM = 64;// To store the states of DPstatic 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 mstatic 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 codepublic 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 npmaxN = 20maxM = 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 approachusing System; class GFG { static int maxN = 20;static int maxM = 64;// To store the states of DPstatic 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 mstatic 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 codepublic 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 approachvar maxN = 20var maxM = 64// To store the states of DPvar 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 mfunction 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 codevar arr = [3, 2, 2, 1];var n = arr.length;var m = 3;document.write( findLen(arr, 0, 0, n, m));</script> |
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 mint 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 codeint 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 mfunction 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 codeconst arr = [3, 2, 2, 1];const n = arr.length;const m = 3;// Function callconsole.log(findLen(arr, n, m)); |
3
Time Complexity: O(N * M)
Auxiliary Space: O(N * M).
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 zambiatek!



