📜  O(sum) 空间中的子集和问题

📅  最后修改于: 2021-09-17 06:55:28             🧑  作者: Mango

给定一个非负整数数组和一个值总和,确定给定集合的子集是否存在总和等于给定总和的子集。

例子:

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 现场工作专业课程学生竞争性编程现场课程