给定一个非负整数数组和一个值总和,确定给定集合的子集是否存在总和等于给定总和的子集。
例子:
Input : arr[] = {4, 1, 10, 12, 5, 2},
sum = 9
Output : TRUE
{4, 5} is a subset with sum 9.
Input : arr[] = {1, 8, 2, 5},
sum = 4
Output : FALSE
There exists no subset with sum 4.
我们在下面的帖子中讨论了基于动态规划的解决方案。
动态规划 |第 25 组(子集和问题)
上面讨论的解决方案需要 O(n * sum) 空间和 O(n * sum) 时间。我们可以优化空间。我们创建了一个布尔二维数组子集[2][sum+1]。使用自下而上的方式我们可以填满这张表。在“subset[2][sum+1]”中使用2背后的想法是填充一行只需要前一行的值。因此,使用交替行将第一个作为当前行,第二个作为前一个,或者第一个作为前一个,第二个作为当前。
C++
// Returns true if there exists a subset
// with given sum in arr[]
#include
#include
bool isSubsetSum(int arr[], int n, int sum)
{
// The value of subset[i%2][j] will be true
// if there exists a subset of sum j in
// arr[0, 1, ...., i-1]
bool subset[2][sum + 1];
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= sum; j++) {
// A subset with sum 0 is always possible
if (j == 0)
subset[i % 2][j] = true;
// If there exists no element no sum
// is possible
else if (i == 0)
subset[i % 2][j] = false;
else if (arr[i - 1] <= j)
subset[i % 2][j] = subset[(i + 1) % 2]
[j - arr[i - 1]] || subset[(i + 1) % 2][j];
else
subset[i % 2][j] = subset[(i + 1) % 2][j];
}
}
return subset[n % 2][sum];
}
// Driver code
int main()
{
int arr[] = { 6, 2, 5 };
int sum = 7;
int n = sizeof(arr) / sizeof(arr[0]);
if (isSubsetSum(arr, n, sum) == true)
printf("There exists a subset with given sum");
else
printf("No subset exists with given sum");
return 0;
}
Java
// Java Program to get a subset with a
// with a sum provided by the user
public class Subset_sum {
// Returns true if there exists a subset
// with given sum in arr[]
static boolean isSubsetSum(int arr[], int n, int sum)
{
// The value of subset[i%2][j] will be true
// if there exists a subset of sum j in
// arr[0, 1, ...., i-1]
boolean subset[][] = new boolean[2][sum + 1];
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= sum; j++) {
// A subset with sum 0 is always possible
if (j == 0)
subset[i % 2][j] = true;
// If there exists no element no sum
// is possible
else if (i == 0)
subset[i % 2][j] = false;
else if (arr[i - 1] <= j)
subset[i % 2][j] = subset[(i + 1) % 2]
[j - arr[i - 1]] || subset[(i + 1) % 2][j];
else
subset[i % 2][j] = subset[(i + 1) % 2][j];
}
}
return subset[n % 2][sum];
}
// Driver code
public static void main(String args[])
{
int arr[] = { 1, 2, 5 };
int sum = 7;
int n = arr.length;
if (isSubsetSum(arr, n, sum) == true)
System.out.println("There exists a subset with" +
"given sum");
else
System.out.println("No subset exists with" +
"given sum");
}
}
// This code is contributed by Sumit Ghosh
Python
# Returns true if there exists a subset
# with given sum in arr[]
def isSubsetSum(arr, n, sum):
# The value of subset[i%2][j] will be true
# if there exists a subset of sum j in
# arr[0, 1, ...., i-1]
subset = [ [False for j in range(sum + 1)] for i in range(3) ]
for i in range(n + 1):
for j in range(sum + 1):
# A subset with sum 0 is always possible
if (j == 0):
subset[i % 2][j] = True
# If there exists no element no sum
# is possible
elif (i == 0):
subset[i % 2][j] = False
elif (arr[i - 1] <= j):
subset[i % 2][j] = subset[(i + 1) % 2][j - arr[i - 1]] or subset[(i + 1)
% 2][j]
else:
subset[i % 2][j] = subset[(i + 1) % 2][j]
return subset[n % 2][sum]
# Driver code
arr = [ 6, 2, 5 ]
sum = 7
n = len(arr)
if (isSubsetSum(arr, n, sum) == True):
print ("There exists a subset with given sum")
else:
print ("No subset exists with given sum")
# This code is contributed by Sachin Bisht
C#
// C# Program to get a subset with a
// with a sum provided by the user
using System;
public class Subset_sum {
// Returns true if there exists a subset
// with given sum in arr[]
static bool isSubsetSum(int []arr, int n, int sum)
{
// The value of subset[i%2][j] will be true
// if there exists a subset of sum j in
// arr[0, 1, ...., i-1]
bool [,]subset = new bool[2,sum + 1];
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= sum; j++) {
// A subset with sum 0 is always possible
if (j == 0)
subset[i % 2,j] = true;
// If there exists no element no sum
// is possible
else if (i == 0)
subset[i % 2,j] = false;
else if (arr[i - 1] <= j)
subset[i % 2,j] = subset[(i + 1) % 2,j - arr[i - 1]] || subset[(i + 1) % 2,j];
else
subset[i % 2,j] = subset[(i + 1) % 2,j];
}
}
return subset[n % 2,sum];
}
// Driver code
public static void Main()
{
int []arr = { 1, 2, 5 };
int sum = 7;
int n = arr.Length;
if (isSubsetSum(arr, n, sum) == true)
Console.WriteLine("There exists a subset with" +
"given sum");
else
Console.WriteLine("No subset exists with" +
"given sum");
}
}
// This code is contributed by Ryuga
PHP
Javascript
C++
#include
using namespace std;
bool isPossible(int elements[], int sum, int n)
{
int dp[sum + 1];
// Initializing with 1 as sum 0 is
// always possible
dp[0] = 1;
// Loop to go through every element of
// the elements array
for(int i = 0; i < n; i++)
{
// To change the values of all possible sum
// values to 1
for(int j = sum; j >= elements[i]; j--)
{
if (dp[j - elements[i]] == 1)
dp[j] = 1;
}
}
// If sum is possible then return 1
if (dp[sum] == 1)
return true;
return false;
}
// Driver code
int main()
{
int elements[] = { 6, 2, 5 };
int n = sizeof(elements) / sizeof(elements[0]);
int sum = 7;
if (isPossible(elements, sum, n))
cout << ("YES");
else
cout << ("NO");
return 0;
}
// This code is contributed by Potta Lokesh
Java
import java.io.*;
import java.util.*;
class GFG {
static boolean isPossible(int elements[], int sum)
{
int dp[] = new int[sum + 1];
// initializing with 1 as sum 0 is always possible
dp[0] = 1;
// loop to go through every element of the elements
// array
for (int i = 0; i < elements.length; i++) {
// to change the values of all possible sum
// values to 1
for (int j = sum; j >= elements[i]; j--) {
if (dp[j - elements[i]] == 1)
dp[j] = 1;
}
}
// if sum is possible then return 1
if (dp[sum] == 1)
return true;
return false;
}
public static void main(String[] args) throws Exception
{
int elements[] = { 6, 2, 5 };
int sum = 7;
if (isPossible(elements, sum))
System.out.println("YES");
else
System.out.println("NO");
}
}
输出
There exists a subset with given sum
另一种方法:为了进一步降低空间复杂度,我们创建了一个布尔一维数组子集[sum+1]。使用自下而上的方式我们可以填满这张表。这个想法是我们可以检查直到位置“i”的总和是否可能,然后如果数组中位置 j 的当前元素是 x,那么总和 i+x 也是可能的。我们从后到前遍历 sum 数组,这样我们就不会将任何元素计数两次。
这是给定方法的代码:
C++
#include
using namespace std;
bool isPossible(int elements[], int sum, int n)
{
int dp[sum + 1];
// Initializing with 1 as sum 0 is
// always possible
dp[0] = 1;
// Loop to go through every element of
// the elements array
for(int i = 0; i < n; i++)
{
// To change the values of all possible sum
// values to 1
for(int j = sum; j >= elements[i]; j--)
{
if (dp[j - elements[i]] == 1)
dp[j] = 1;
}
}
// If sum is possible then return 1
if (dp[sum] == 1)
return true;
return false;
}
// Driver code
int main()
{
int elements[] = { 6, 2, 5 };
int n = sizeof(elements) / sizeof(elements[0]);
int sum = 7;
if (isPossible(elements, sum, n))
cout << ("YES");
else
cout << ("NO");
return 0;
}
// This code is contributed by Potta Lokesh
Java
import java.io.*;
import java.util.*;
class GFG {
static boolean isPossible(int elements[], int sum)
{
int dp[] = new int[sum + 1];
// initializing with 1 as sum 0 is always possible
dp[0] = 1;
// loop to go through every element of the elements
// array
for (int i = 0; i < elements.length; i++) {
// to change the values of all possible sum
// values to 1
for (int j = sum; j >= elements[i]; j--) {
if (dp[j - elements[i]] == 1)
dp[j] = 1;
}
}
// if sum is possible then return 1
if (dp[sum] == 1)
return true;
return false;
}
public static void main(String[] args) throws Exception
{
int elements[] = { 6, 2, 5 };
int sum = 7;
if (isPossible(elements, sum))
System.out.println("YES");
else
System.out.println("NO");
}
}
输出
YES
时间复杂度: O(N*K),其中 N 是数组中元素的数量,K 是总和。
空间复杂度: O(K)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。