📌  相关文章
📜  最长子序列,其总和可被给定数整除

📅  最后修改于: 2021-05-06 18:37:15             🧑  作者: Mango

给定数组arr []和整数M ,任务是找到最长子序列的长度,该子序列的和可被M整除。如果没有这样的子序列,则打印0

例子:

方法:一种简单的解决方法是生成所有可能的子序列,然后找到其中最大的可分解子序列,其和可被M整除。但是,对于较小的M值,可以使用基于动态编程的方法。
我们先来看一下递归关系。

现在让我们了解DP的状态。在这里, dp [i] [curr_mod]存储子数组arr [i … N-1]的最长子序列,以使该子序列和curr_mod的和可被M整除。在每个步骤中,可以选择索引i更新curr_mod或将其忽略。

另外,请注意,只需要存储SUM%m即可,而不是全部和,因为此信息足以完成DP的状态。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
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


输出:
3

时间复杂度: O(N * M)