给定一个长度为N的数组arr[]和一个整数X ,任务是找到总和等于X的子集的数量。
例子:
Input: arr[] = {1, 2, 3, 3}, X = 6
Output: 3
All the possible subsets are {1, 2, 3},
{1, 2, 3} and {3, 3}
Input: arr[] = {1, 1, 1, 1}, X = 1
Output: 4
方法:一个简单的方法是通过生成所有可能的子集,然后检查该子集是否具有所需的总和来解决此问题。这种方法将具有指数时间复杂度。但是,对于较小的X值和数组元素,可以使用动态规划解决此问题。
我们先来看递归关系。
此方法对所有整数都有效。
dp[i][C] = dp[i – 1][C – arr[i]] + dp[i – 1][C]
现在让我们了解 DP 的状态。这里, dp[i][C]存储子数组arr[i…N-1]的子集数量,使得它们的总和等于C 。
因此,递归是非常微不足道的,因为只有两种选择,即要么考虑子集中的第i个元素,要么不考虑。
下面是上述方法的实现:
C++
// C++ implementation of the approach
#include
using namespace std;
#define maxN 20
#define maxSum 50
#define minSum 50
#define base 50
// To store the states of DP
int dp[maxN][maxSum + minSum];
bool v[maxN][maxSum + minSum];
// Function to return the required count
int findCnt(int* arr, int i, int required_sum, int n)
{
// Base case
if (i == n) {
if (required_sum == 0)
return 1;
else
return 0;
}
// If the state has been solved before
// return the value of the state
if (v[i][required_sum + base])
return dp[i][required_sum + base];
// Setting the state as solved
v[i][required_sum + base] = 1;
// Recurrence relation
dp[i][required_sum + base]
= findCnt(arr, i + 1, required_sum, n)
+ findCnt(arr, i + 1, required_sum - arr[i], n);
return dp[i][required_sum + base];
}
// Driver code
int main()
{
int arr[] = { 3, 3, 3, 3 };
int n = sizeof(arr) / sizeof(int);
int x = 6;
cout << findCnt(arr, 0, x, n);
return 0;
}
Java
// Java implementation of the approach
import java.util.*;
class GFG
{
static int maxN = 20;
static int maxSum = 50;
static int minSum = 50;
static int base = 50;
// To store the states of DP
static int [][]dp = new int[maxN][maxSum + minSum];
static boolean [][]v = new boolean[maxN][maxSum + minSum];
// Function to return the required count
static int findCnt(int []arr, int i,
int required_sum, int n)
{
// Base case
if (i == n)
{
if (required_sum == 0)
return 1;
else
return 0;
}
// If the state has been solved before
// return the value of the state
if (v[i][required_sum + base])
return dp[i][required_sum + base];
// Setting the state as solved
v[i][required_sum + base] = true;
// Recurrence relation
dp[i][required_sum + base] =
findCnt(arr, i + 1, required_sum, n) +
findCnt(arr, i + 1, required_sum - arr[i], n);
return dp[i][required_sum + base];
}
// Driver code
public static void main(String []args)
{
int arr[] = { 3, 3, 3, 3 };
int n = arr.length;
int x = 6;
System.out.println(findCnt(arr, 0, x, n));
}
}
// This code is contributed by 29AjayKumar
Python3
# Python3 implementation of the approach
import numpy as np
maxN = 20
maxSum = 50
minSum = 50
base = 50
# To store the states of DP
dp = np.zeros((maxN, maxSum + minSum));
v = np.zeros((maxN, maxSum + minSum));
# Function to return the required count
def findCnt(arr, i, required_sum, n) :
# Base case
if (i == n) :
if (required_sum == 0) :
return 1;
else :
return 0;
# If the state has been solved before
# return the value of the state
if (v[i][required_sum + base]) :
return dp[i][required_sum + base];
# Setting the state as solved
v[i][required_sum + base] = 1;
# Recurrence relation
dp[i][required_sum + base] = findCnt(arr, i + 1,
required_sum, n) + \
findCnt(arr, i + 1,
required_sum - arr[i], n);
return dp[i][required_sum + base];
# Driver code
if __name__ == "__main__" :
arr = [ 3, 3, 3, 3 ];
n = len(arr);
x = 6;
print(findCnt(arr, 0, x, n));
# This code is contributed by AnkitRai01
C#
// C# implementation of the approach
using System;
class GFG
{
static int maxN = 20;
static int maxSum = 50;
static int minSum = 50;
static int Base = 50;
// To store the states of DP
static int [,]dp = new int[maxN, maxSum + minSum];
static Boolean [,]v = new Boolean[maxN, maxSum + minSum];
// Function to return the required count
static int findCnt(int []arr, int i,
int required_sum, int n)
{
// Base case
if (i == n)
{
if (required_sum == 0)
return 1;
else
return 0;
}
// If the state has been solved before
// return the value of the state
if (v[i, required_sum + Base])
return dp[i, required_sum + Base];
// Setting the state as solved
v[i, required_sum + Base] = true;
// Recurrence relation
dp[i, required_sum + Base] =
findCnt(arr, i + 1, required_sum, n) +
findCnt(arr, i + 1, required_sum - arr[i], n);
return dp[i,required_sum + Base];
}
// Driver code
public static void Main(String []args)
{
int []arr = { 3, 3, 3, 3 };
int n = arr.Length;
int x = 6;
Console.WriteLine(findCnt(arr, 0, x, n));
}
}
// This code is contributed by 29AjayKumar
Javascript
C++
#include
using namespace std;
int subsetSum(int a[], int n, int sum)
{
// Initializing the matrix
int tab[n + 1][sum + 1];
// Initializing the first value of matrix
tab[0][0] = 1;
for (int i = 1; i <= sum; i++)
tab[0][i] = 0;
for (int i = 1; i <= n; i++)
tab[i][0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= sum; j++)
{
// if the value is greater than the sum
if (a[i - 1] > j)
tab[i][j] = tab[i - 1][j];
else
{
tab[i][j] = tab[i - 1][j] + tab[i - 1][j - a[i - 1]];
}
}
}
return tab[n][sum];
}
int main()
{
int n = 4;
int a[] = {3,3,3,3};
int sum = 6;
cout << (subsetSum(a, n, sum));
}
Java
import java.io.*;
import java.lang.*;
import java.util.*;
class GFG{
static int subsetSum(int a[], int n, int sum)
{
// Initializing the matrix
int tab[][] = new int[n + 1][sum + 1];
// Initializing the first value of matrix
tab[0][0] = 1;
for(int i = 1; i <= sum; i++)
tab[0][i] = 0;
for(int i = 1; i <= n; i++)
tab[i][0] = 1;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= sum; j++)
{
// If the value is greater than the sum
if (a[i - 1] > j)
tab[i][j] = tab[i - 1][j];
else
{
tab[i][j] = tab[i - 1][j] +
tab[i - 1][j - a[i - 1]];
}
}
}
return tab[n][sum];
}
// Driver Code
public static void main(String[] args)
{
int n = 4;
int a[] = { 3, 3, 3, 3 };
int sum = 6;
System.out.print(subsetSum(a, n, sum));
}
}
// This code is contributed by Kingash
6
方法二:使用制表法:
This method is valid only for those arrays which contains positive elements.
In this method we use a 2D array of size (arr.size() + 1) * (target + 1) of type integer.
Initialization of Matrix:
mat[0][0] = 1 because If the size of sum is
if (A[i] > j)
DP[i][j] = DP[i-1][j]
else
DP[i][j] = DP[i-1][j] + DP[i-1][j-A[i]]
这意味着如果当前元素的值大于“当前总和值”,我们将复制之前案例的答案
如果当前的总和值大于 ‘ith’ 元素,我们将看到是否有任何先前的状态已经经历过 sum=’j’ 并且任何先前的状态经历了一个值 ‘j – A[i]’ 这将解决我们的目的
C++
#include
using namespace std;
int subsetSum(int a[], int n, int sum)
{
// Initializing the matrix
int tab[n + 1][sum + 1];
// Initializing the first value of matrix
tab[0][0] = 1;
for (int i = 1; i <= sum; i++)
tab[0][i] = 0;
for (int i = 1; i <= n; i++)
tab[i][0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= sum; j++)
{
// if the value is greater than the sum
if (a[i - 1] > j)
tab[i][j] = tab[i - 1][j];
else
{
tab[i][j] = tab[i - 1][j] + tab[i - 1][j - a[i - 1]];
}
}
}
return tab[n][sum];
}
int main()
{
int n = 4;
int a[] = {3,3,3,3};
int sum = 6;
cout << (subsetSum(a, n, sum));
}
Java
import java.io.*;
import java.lang.*;
import java.util.*;
class GFG{
static int subsetSum(int a[], int n, int sum)
{
// Initializing the matrix
int tab[][] = new int[n + 1][sum + 1];
// Initializing the first value of matrix
tab[0][0] = 1;
for(int i = 1; i <= sum; i++)
tab[0][i] = 0;
for(int i = 1; i <= n; i++)
tab[i][0] = 1;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= sum; j++)
{
// If the value is greater than the sum
if (a[i - 1] > j)
tab[i][j] = tab[i - 1][j];
else
{
tab[i][j] = tab[i - 1][j] +
tab[i - 1][j - a[i - 1]];
}
}
}
return tab[n][sum];
}
// Driver Code
public static void main(String[] args)
{
int n = 4;
int a[] = { 3, 3, 3, 3 };
int sum = 6;
System.out.print(subsetSum(a, n, sum));
}
}
// This code is contributed by Kingash
6
时间复杂度: O(sum*n),其中总和是“目标总和”,“n”是数组的大小。
辅助空间: O(sum*n),作为二维数组的大小,是sum*n。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。