给定一组非负整数和一个值sum ,确定给定集合的子集是否存在 sum 等于给定sum的子集。
例子:
Input: set[] = {3, 34, 4, 12, 5, 2}, sum = 9
Output: True
There is a subset (4, 5) with sum 9.
Input: set[] = {3, 34, 4, 12, 5, 2}, sum = 30
Output: False
There is no subset that add up to 30.
方法一:递归。
方法:对于递归方法,我们将考虑两种情况。
- 考虑最后一个元素,现在所需的总和 = 目标总和 – “最后”元素的值和元素数量 = 总元素 – 1
- 保留“最后一个”元素,现在所需的总和 = 目标总和和元素数 = 总元素 – 1
以下是 isSubsetSum() 问题的递归公式。
isSubsetSum(set, n, sum)
= isSubsetSum(set, n-1, sum) ||
isSubsetSum(set, n-1, sum-set[n-1])
Base Cases:
isSubsetSum(set, n, sum) = false, if sum > 0 and n == 0
isSubsetSum(set, n, sum) = true, if sum == 0
让我们来看看上述方法的模拟-:
set[]={3, 4, 5, 2}
sum=9
(x, y)= 'x' is the left number of elements,
'y' is the required sum
(4, 9)
{True}
/ \
(3, 6) (3, 9)
/ \ / \
(2, 2) (2, 6) (2, 5) (2, 9)
{True}
/ \
(1, -3) (1, 2)
{False} {True}
/ \
(0, 0) (0, 2)
{True} {False}
C++
// A recursive solution for subset sum problem
#include
// Returns true if there is a subset
// of set[] with sum equal to given sum
bool isSubsetSum(int set[], int n, int sum)
{
// Base Cases
if (sum == 0)
return true;
if (n == 0)
return false;
// If last element is greater than sum,
// then ignore it
if (set[n - 1] > sum)
return isSubsetSum(set, n - 1, sum);
/* else, check if sum can be obtained by any
of the following:
(a) including the last element
(b) excluding the last element */
return isSubsetSum(set, n - 1, sum)
|| isSubsetSum(set, n - 1, sum - set[n - 1]);
}
// Driver code
int main()
{
int set[] = { 3, 34, 4, 12, 5, 2 };
int sum = 9;
int n = sizeof(set) / sizeof(set[0]);
if (isSubsetSum(set, n, sum) == true)
printf("Found a subset with given sum");
else
printf("No subset with given sum");
return 0;
}
Java
// A recursive solution for subset sum
// problem
class GFG {
// Returns true if there is a subset
// of set[] with sum equal to given sum
static boolean isSubsetSum(int set[],
int n, int sum)
{
// Base Cases
if (sum == 0)
return true;
if (n == 0)
return false;
// If last element is greater than
// sum, then ignore it
if (set[n - 1] > sum)
return isSubsetSum(set, n - 1, sum);
/* else, check if sum can be obtained
by any of the following
(a) including the last element
(b) excluding the last element */
return isSubsetSum(set, n - 1, sum)
|| isSubsetSum(set, n - 1, sum - set[n - 1]);
}
/* Driver code */
public static void main(String args[])
{
int set[] = { 3, 34, 4, 12, 5, 2 };
int sum = 9;
int n = set.length;
if (isSubsetSum(set, n, sum) == true)
System.out.println("Found a subset"
+ " with given sum");
else
System.out.println("No subset with"
+ " given sum");
}
}
/* This code is contributed by Rajat Mishra */
Python3
# A recursive solution for subset sum
# problem
# Returns true if there is a subset
# of set[] with sun equal to given sum
def isSubsetSum(set, n, sum):
# Base Cases
if (sum == 0):
return True
if (n == 0):
return False
# If last element is greater than
# sum, then ignore it
if (set[n - 1] > sum):
return isSubsetSum(set, n - 1, sum)
# else, check if sum can be obtained
# by any of the following
# (a) including the last element
# (b) excluding the last element
return isSubsetSum(
set, n-1, sum) or isSubsetSum(
set, n-1, sum-set[n-1])
# Driver code
set = [3, 34, 4, 12, 5, 2]
sum = 9
n = len(set)
if (isSubsetSum(set, n, sum) == True):
print("Found a subset with given sum")
else:
print("No subset with given sum")
# This code is contributed by Nikita Tiwari.
C#
// A recursive solution for subset sum problem
using System;
class GFG {
// Returns true if there is a subset of set[] with sum
// equal to given sum
static bool isSubsetSum(int[] set, int n, int sum)
{
// Base Cases
if (sum == 0)
return true;
if (n == 0)
return false;
// If last element is greater than sum,
// then ignore it
if (set[n - 1] > sum)
return isSubsetSum(set, n - 1, sum);
/* else, check if sum can be obtained
by any of the following
(a) including the last element
(b) excluding the last element */
return isSubsetSum(set, n - 1, sum)
|| isSubsetSum(set, n - 1, sum - set[n - 1]);
}
// Driver code
public static void Main()
{
int[] set = { 3, 34, 4, 12, 5, 2 };
int sum = 9;
int n = set.Length;
if (isSubsetSum(set, n, sum) == true)
Console.WriteLine("Found a subset with given sum");
else
Console.WriteLine("No subset with given sum");
}
}
// This code is contributed by Sam007
PHP
$sum)
return isSubsetSum($set, $n - 1, $sum);
/* else, check if sum can be
obtained by any of the following
(a) including the last element
(b) excluding the last element */
return isSubsetSum($set, $n - 1, $sum) ||
isSubsetSum($set, $n - 1,
$sum - $set[$n - 1]);
}
// Driver Code
$set = array(3, 34, 4, 12, 5, 2);
$sum = 9;
$n = 6;
if (isSubsetSum($set, $n, $sum) == true)
echo"Found a subset with given sum";
else
echo "No subset with given sum";
// This code is contributed by Anuj_67
?>
Javascript
C++
// A Dynamic Programming solution
// for subset sum problem
#include
// Returns true if there is a subset of set[]
// with sun equal to given sum
bool isSubsetSum(int set[], int n, int sum)
{
// The value of subset[i][j] will be true if
// there is a subset of set[0..j-1] with sum
// equal to i
bool subset[n + 1][sum + 1];
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
subset[i][0] = true;
// If sum is not 0 and set is empty,
// then answer is false
for (int i = 1; i <= sum; i++)
subset[0][i] = false;
// Fill the subset table in botton up manner
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= sum; j++) {
if (j < set[i - 1])
subset[i][j] = subset[i - 1][j];
if (j >= set[i - 1])
subset[i][j] = subset[i - 1][j]
|| subset[i - 1][j - set[i - 1]];
}
}
/* // uncomment this code to print table
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= sum; j++)
printf ("%4d", subset[i][j]);
printf("\n");
}*/
return subset[n][sum];
}
// Driver code
int main()
{
int set[] = { 3, 34, 4, 12, 5, 2 };
int sum = 9;
int n = sizeof(set) / sizeof(set[0]);
if (isSubsetSum(set, n, sum) == true)
printf("Found a subset with given sum");
else
printf("No subset with given sum");
return 0;
}
// This code is contributed by Arjun Tyagi.
Java
// A Dynamic Programming solution for subset
// sum problem
class GFG {
// Returns true if there is a subset of
// set[] with sun equal to given sum
static boolean isSubsetSum(int set[],
int n, int sum)
{
// The value of subset[i][j] will be
// true if there is a subset of
// set[0..j-1] with sum equal to i
boolean subset[][] = new boolean[sum + 1][n + 1];
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
subset[0][i] = true;
// If sum is not 0 and set is empty,
// then answer is false
for (int i = 1; i <= sum; i++)
subset[i][0] = false;
// Fill the subset table in botton
// up manner
for (int i = 1; i <= sum; i++) {
for (int j = 1; j <= n; j++) {
subset[i][j] = subset[i][j - 1];
if (i >= set[j - 1])
subset[i][j] = subset[i][j]
|| subset[i - set[j - 1]][j - 1];
}
}
/* // uncomment this code to print table
for (int i = 0; i <= sum; i++)
{
for (int j = 0; j <= n; j++)
System.out.println (subset[i][j]);
} */
return subset[sum][n];
}
/* Driver code*/
public static void main(String args[])
{
int set[] = { 3, 34, 4, 12, 5, 2 };
int sum = 9;
int n = set.length;
if (isSubsetSum(set, n, sum) == true)
System.out.println("Found a subset"
+ " with given sum");
else
System.out.println("No subset with"
+ " given sum");
}
}
/* This code is contributed by Rajat Mishra */
Python3
# A Dynamic Programming solution for subset
# sum problem Returns true if there is a subset of
# set[] with sun equal to given sum
# Returns true if there is a subset of set[]
# with sun equal to given sum
def isSubsetSum(set, n, sum):
# The value of subset[i][j] will be
# true if there is a
# subset of set[0..j-1] with sum equal to i
subset =([[False for i in range(sum + 1)]
for i in range(n + 1)])
# If sum is 0, then answer is true
for i in range(n + 1):
subset[i][0] = True
# If sum is not 0 and set is empty,
# then answer is false
for i in range(1, sum + 1):
subset[0][i]= False
# Fill the subset table in botton up manner
for i in range(1, n + 1):
for j in range(1, sum + 1):
if j= set[i-1]:
subset[i][j] = (subset[i-1][j] or
subset[i - 1][j-set[i-1]])
# uncomment this code to print table
# for i in range(n + 1):
# for j in range(sum + 1):
# print (subset[i][j], end =" ")
# print()
return subset[n][sum]
# Driver code
if __name__=='__main__':
set = [3, 34, 4, 12, 5, 2]
sum = 9
n = len(set)
if (isSubsetSum(set, n, sum) == True):
print("Found a subset with given sum")
else:
print("No subset with given sum")
# This code is contributed by
# sahil shelangia.
C#
// A Dynamic Programming solution for
// subset sum problem
using System;
class GFG {
// Returns true if there is a subset
// of set[] with sun equal to given sum
static bool isSubsetSum(int[] set, int n, int sum)
{
// The value of subset[i][j] will be true if there
// is a subset of set[0..j-1] with sum equal to i
bool[, ] subset = new bool[sum + 1, n + 1];
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
subset[0, i] = true;
// If sum is not 0 and set is empty,
// then answer is false
for (int i = 1; i <= sum; i++)
subset[i, 0] = false;
// Fill the subset table in bottom up manner
for (int i = 1; i <= sum; i++) {
for (int j = 1; j <= n; j++) {
subset[i, j] = subset[i, j - 1];
if (i >= set[j - 1])
subset[i, j] = subset[i, j]
|| subset[i - set[j - 1], j - 1];
}
}
return subset[sum, n];
}
// Driver code
public static void Main()
{
int[] set = { 3, 34, 4, 12, 5, 2 };
int sum = 9;
int n = set.Length;
if (isSubsetSum(set, n, sum) == true)
Console.WriteLine("Found a subset with given sum");
else
Console.WriteLine("No subset with given sum");
}
}
// This code is contributed by Sam007
PHP
= $set[$i-1])
$subset[$i][$j] =
$subset[$i-1][$j] ||
$subset[$i - 1][$j -
$set[$i-1]];
}
}
/* // uncomment this code to print table
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= sum; j++)
printf ("%4d", subset[i][j]);
printf("n");
}*/
return $subset[$n][$sum];
}
// Driver code
$set = array(3, 34, 4, 12, 5, 2);
$sum = 9;
$n = count($set);
if (isSubsetSum($set, $n, $sum) == true)
echo "Found a subset with given sum";
else
echo "No subset with given sum";
// This code is contributed by anuj_67.
?>
Javascript
C++
// CPP program for the above approach
#include
using namespace std;
// Taking the matrix as globally
int tab[2000][2000];
// Check if possible subset with
// given sum is possible or not
int subsetSum(int a[], int n, int sum)
{
// If the sum is zero it means
// we got our expected sum
if (sum == 0)
return 1;
if (n <= 0)
return 0;
// If the value is not -1 it means it
// already call the function
// with the same value.
// it will save our from the repetation.
if (tab[n - 1][sum] != -1)
return tab[n - 1][sum];
// if the value of a[n-1] is
// greater than the sum.
// we call for the next value
if (a[n - 1] > sum)
return tab[n - 1][sum] = subsetSum(a, n - 1, sum);
else
{
// Here we do two calls because we
// don't know which value is
// full-fill our critaria
// that's why we doing two calls
return tab[n - 1][sum] = subsetSum(a, n - 1, sum) ||
subsetSum(a, n - 1, sum - a[n - 1]);
}
}
// Driver Code
int main()
{
// Storing the value -1 to the matrix
memset(tab, -1, sizeof(tab));
int n = 5;
int a[] = {1, 5, 3, 7, 4};
int sum = 12;
if (subsetSum(a, n, sum))
{
cout << "YES" << endl;
}
else
cout << "NO" << endl;
/* This Code is Contributed by Ankit Kumar*/
}
Javascript
输出
Found a subset with given sum
复杂性分析:上述解决方案可能会在最坏情况下尝试给定集合的所有子集。因此上述解决方案的时间复杂度是指数级的。问题实际上是 NP-Complete(此问题没有已知的多项式时间解决方案)。
方法2 :使用动态规划解决伪多项式时间问题。
所以我们将创建一个大小为 (arr.size() + 1) * (target + 1) 的boolean类型的二维数组。如果存在来自 A[0…. i ] 且总和值 = ‘j’的元素子集,则状态 DP[i][j] 将为真。问题的处理方法是:
if (A[i-1] > j)
DP[i][j] = DP[i-1][j]
else
DP[i][j] = DP[i-1][j] OR DP[i-1][j-A[i-1]]
- 这意味着如果当前元素的值大于“当前总和值”,我们将复制以前案例的答案
- 如果当前的总和值大于 ‘ith’ 元素,我们将查看是否有任何先前的状态已经经历过sum=’j’ 或任何先前的状态经历了一个值 ‘j – A[i]’这将解决我们的问题目的。
下面的模拟将阐明上述方法:
set[]={3, 4, 5, 2}
target=6
0 1 2 3 4 5 6
0 T F F F F F F
3 T F F T F F F
4 T F F T T F F
5 T F F T T T F
2 T F T T T T T
下面是上述方法的实现:
C++
// A Dynamic Programming solution
// for subset sum problem
#include
// Returns true if there is a subset of set[]
// with sun equal to given sum
bool isSubsetSum(int set[], int n, int sum)
{
// The value of subset[i][j] will be true if
// there is a subset of set[0..j-1] with sum
// equal to i
bool subset[n + 1][sum + 1];
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
subset[i][0] = true;
// If sum is not 0 and set is empty,
// then answer is false
for (int i = 1; i <= sum; i++)
subset[0][i] = false;
// Fill the subset table in botton up manner
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= sum; j++) {
if (j < set[i - 1])
subset[i][j] = subset[i - 1][j];
if (j >= set[i - 1])
subset[i][j] = subset[i - 1][j]
|| subset[i - 1][j - set[i - 1]];
}
}
/* // uncomment this code to print table
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= sum; j++)
printf ("%4d", subset[i][j]);
printf("\n");
}*/
return subset[n][sum];
}
// Driver code
int main()
{
int set[] = { 3, 34, 4, 12, 5, 2 };
int sum = 9;
int n = sizeof(set) / sizeof(set[0]);
if (isSubsetSum(set, n, sum) == true)
printf("Found a subset with given sum");
else
printf("No subset with given sum");
return 0;
}
// This code is contributed by Arjun Tyagi.
Java
// A Dynamic Programming solution for subset
// sum problem
class GFG {
// Returns true if there is a subset of
// set[] with sun equal to given sum
static boolean isSubsetSum(int set[],
int n, int sum)
{
// The value of subset[i][j] will be
// true if there is a subset of
// set[0..j-1] with sum equal to i
boolean subset[][] = new boolean[sum + 1][n + 1];
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
subset[0][i] = true;
// If sum is not 0 and set is empty,
// then answer is false
for (int i = 1; i <= sum; i++)
subset[i][0] = false;
// Fill the subset table in botton
// up manner
for (int i = 1; i <= sum; i++) {
for (int j = 1; j <= n; j++) {
subset[i][j] = subset[i][j - 1];
if (i >= set[j - 1])
subset[i][j] = subset[i][j]
|| subset[i - set[j - 1]][j - 1];
}
}
/* // uncomment this code to print table
for (int i = 0; i <= sum; i++)
{
for (int j = 0; j <= n; j++)
System.out.println (subset[i][j]);
} */
return subset[sum][n];
}
/* Driver code*/
public static void main(String args[])
{
int set[] = { 3, 34, 4, 12, 5, 2 };
int sum = 9;
int n = set.length;
if (isSubsetSum(set, n, sum) == true)
System.out.println("Found a subset"
+ " with given sum");
else
System.out.println("No subset with"
+ " given sum");
}
}
/* This code is contributed by Rajat Mishra */
蟒蛇3
# A Dynamic Programming solution for subset
# sum problem Returns true if there is a subset of
# set[] with sun equal to given sum
# Returns true if there is a subset of set[]
# with sun equal to given sum
def isSubsetSum(set, n, sum):
# The value of subset[i][j] will be
# true if there is a
# subset of set[0..j-1] with sum equal to i
subset =([[False for i in range(sum + 1)]
for i in range(n + 1)])
# If sum is 0, then answer is true
for i in range(n + 1):
subset[i][0] = True
# If sum is not 0 and set is empty,
# then answer is false
for i in range(1, sum + 1):
subset[0][i]= False
# Fill the subset table in botton up manner
for i in range(1, n + 1):
for j in range(1, sum + 1):
if j= set[i-1]:
subset[i][j] = (subset[i-1][j] or
subset[i - 1][j-set[i-1]])
# uncomment this code to print table
# for i in range(n + 1):
# for j in range(sum + 1):
# print (subset[i][j], end =" ")
# print()
return subset[n][sum]
# Driver code
if __name__=='__main__':
set = [3, 34, 4, 12, 5, 2]
sum = 9
n = len(set)
if (isSubsetSum(set, n, sum) == True):
print("Found a subset with given sum")
else:
print("No subset with given sum")
# This code is contributed by
# sahil shelangia.
C#
// A Dynamic Programming solution for
// subset sum problem
using System;
class GFG {
// Returns true if there is a subset
// of set[] with sun equal to given sum
static bool isSubsetSum(int[] set, int n, int sum)
{
// The value of subset[i][j] will be true if there
// is a subset of set[0..j-1] with sum equal to i
bool[, ] subset = new bool[sum + 1, n + 1];
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
subset[0, i] = true;
// If sum is not 0 and set is empty,
// then answer is false
for (int i = 1; i <= sum; i++)
subset[i, 0] = false;
// Fill the subset table in bottom up manner
for (int i = 1; i <= sum; i++) {
for (int j = 1; j <= n; j++) {
subset[i, j] = subset[i, j - 1];
if (i >= set[j - 1])
subset[i, j] = subset[i, j]
|| subset[i - set[j - 1], j - 1];
}
}
return subset[sum, n];
}
// Driver code
public static void Main()
{
int[] set = { 3, 34, 4, 12, 5, 2 };
int sum = 9;
int n = set.Length;
if (isSubsetSum(set, n, sum) == true)
Console.WriteLine("Found a subset with given sum");
else
Console.WriteLine("No subset with given sum");
}
}
// This code is contributed by Sam007
PHP
= $set[$i-1])
$subset[$i][$j] =
$subset[$i-1][$j] ||
$subset[$i - 1][$j -
$set[$i-1]];
}
}
/* // uncomment this code to print table
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= sum; j++)
printf ("%4d", subset[i][j]);
printf("n");
}*/
return $subset[$n][$sum];
}
// Driver code
$set = array(3, 34, 4, 12, 5, 2);
$sum = 9;
$n = count($set);
if (isSubsetSum($set, $n, $sum) == true)
echo "Found a subset with given sum";
else
echo "No subset with given sum";
// This code is contributed by anuj_67.
?>
Javascript
输出
Found a subset with given sum
查找子集和的记忆技术:
方法:
- 在这种方法中,我们也遵循递归方法,但在这种方法中,我们使用另一个二维矩阵,首先用 -1 或任何负值进行初始化。
- 在这种方法中,我们避免了少数重复的递归调用,这就是我们使用二维矩阵的原因。在这个矩阵中,我们存储了前一个调用值的值。
下面是上述方法的实现:
C++
// CPP program for the above approach
#include
using namespace std;
// Taking the matrix as globally
int tab[2000][2000];
// Check if possible subset with
// given sum is possible or not
int subsetSum(int a[], int n, int sum)
{
// If the sum is zero it means
// we got our expected sum
if (sum == 0)
return 1;
if (n <= 0)
return 0;
// If the value is not -1 it means it
// already call the function
// with the same value.
// it will save our from the repetation.
if (tab[n - 1][sum] != -1)
return tab[n - 1][sum];
// if the value of a[n-1] is
// greater than the sum.
// we call for the next value
if (a[n - 1] > sum)
return tab[n - 1][sum] = subsetSum(a, n - 1, sum);
else
{
// Here we do two calls because we
// don't know which value is
// full-fill our critaria
// that's why we doing two calls
return tab[n - 1][sum] = subsetSum(a, n - 1, sum) ||
subsetSum(a, n - 1, sum - a[n - 1]);
}
}
// Driver Code
int main()
{
// Storing the value -1 to the matrix
memset(tab, -1, sizeof(tab));
int n = 5;
int a[] = {1, 5, 3, 7, 4};
int sum = 12;
if (subsetSum(a, n, sum))
{
cout << "YES" << endl;
}
else
cout << "NO" << endl;
/* This Code is Contributed by Ankit Kumar*/
}
Javascript
输出
YES
复杂度分析:
- 时间复杂度: O(sum*n),其中 sum 是“目标总和”,“n”是数组的大小。
- 辅助空间: O(sum*n),因为二维数组的大小是 sum*n。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。