Самая длинная подпоследовательность, сумма которой делится на заданное число

Опубликовано: 12 Января, 2022

Для массива arr [] и целого числа M задача состоит в том, чтобы найти длину самой длинной подпоследовательности, сумма которой делится на M. Если такой подпоследовательности нет, выведите 0 .
Примеры:

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:
 

Рекомендуется: сначала попробуйте свой подход в {IDE}, прежде чем переходить к решению.

Подход: простой способ решить эту проблему - сгенерировать все возможные подпоследовательности, а затем найти среди них наибольшую делимую, сумма которой делится на M. Однако для меньших значений M можно использовать подход, основанный на динамическом программировании.
Давайте сначала посмотрим на рекуррентное отношение.

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

 

Сложность времени: O (N * M)

Вниманию читателя! Не прекращайте учиться сейчас. Освойте все важные концепции DSA с помощью самостоятельного курса DSA по приемлемой для студентов цене и будьте готовы к работе в отрасли. Чтобы завершить подготовку от изучения языка к DS Algo и многому другому, см. Полный курс подготовки к собеседованию .

Если вы хотите посещать живые занятия с отраслевыми экспертами, пожалуйста, обращайтесь к Geeks Classes Live и Geeks Classes Live USA.