找到总和为特定值的所有子集

时间:2013-08-19 03:03:30

标签: algorithm recursion subset

给定一组数字:{1,3,2,5,4,9},找到总和为特定值的子集数(例如,本例中为9)。

这类似于子集求和问题,略有不同,不是检查集合是否有一个总和为9的子集,我们必须找到这样的子集的数量。我正在遵循子集求和问题here的解决方案。但我想知道如何修改它以返回子集的数量。

18 个答案:

答案 0 :(得分:31)

def total_subsets_matching_sum(numbers, sum):
    array = [1] + [0] * (sum)
    for current_number in numbers:
        for num in xrange(sum - current_number, -1, -1):
            if array[num]:
                array[num + current_number] += array[num]
    return array[sum]

assert(total_subsets_matching_sum(range(1, 10), 9)       == 8)
assert(total_subsets_matching_sum({1, 3, 2, 5, 4, 9}, 9) == 4)

<强>解释

这是经典问题之一。我们的想法是找到当前数字的可能总和数。确实如此,只有一种方法可以将总和加到0.开始时,我们只有一个数字。我们从目标开始(解决方案中的变量Maximum)并减去该数字。如果可以得到该数字的总和(对应于该数字的数组元素不为零),则将其添加到与当前数字对应的数组元素中。这个程序会更容易理解

for current_number in numbers:
    for num in xrange(sum, current_number - 1, -1):
        if array[num - current_number]:
            array[num] += array[num - current_number]

当数字为1时,只有一种方法可以得出1的总和(1-1变为0,对应0的元素为1)。所以数组就像这样(记住元素零将有1)

[1, 1, 0, 0, 0, 0, 0, 0, 0, 0]

现在,第二个数字是2.我们开始从9减去2并且它无效(因为7的数组元素是零,我们跳过它)我们一直这样做直到3.当它的3,3 - 2是1并且对应于1的数组元素是1,我们将它添加到3的数组元素中,当它的2,2-2变为0时,我们将值0对应于2的数组元素。在此迭代之后,数组看起来像这样

[1, 1, 1, 1, 0, 0, 0, 0, 0, 0]

我们一直这样做,直到我们处理完所有数字并且每次迭代后的数组看起来像这样

[1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
[1, 1, 1, 2, 1, 1, 1, 0, 0, 0]
[1, 1, 1, 2, 2, 2, 2, 2, 1, 1]
[1, 1, 1, 2, 2, 3, 3, 3, 3, 3]
[1, 1, 1, 2, 2, 3, 4, 4, 4, 5]
[1, 1, 1, 2, 2, 3, 4, 5, 5, 6]
[1, 1, 1, 2, 2, 3, 4, 5, 6, 7]
[1, 1, 1, 2, 2, 3, 4, 5, 6, 8]

在最后一次迭代之后,我们会考虑所有数字和获取目标的方法的数量将是与目标值对应的数组元素。在我们的例子中,最后一次迭代后的Array [9]是8。

答案 1 :(得分:16)

您可以使用动态编程。 Algo复杂度为 O(Sum * N)并使用 O(Sum)内存。

这是我在C#中的实现:

private static int GetmNumberOfSubsets(int[] numbers, int sum)
{
    int[] dp = new int[sum + 1];
    dp[0] = 1;
    int currentSum =0;
    for (int i = 0; i < numbers.Length; i++)
    {
        currentSum += numbers[i];
        for (int j = Math.Min(sum, currentSum); j >= numbers[i]; j--)
            dp[j] += dp[j - numbers[i]];
    }

    return dp[sum];
}

注释:由于子集的数量可能为2 ^ N,因此很容易溢出int类型。

Algo仅适用于正数。

答案 2 :(得分:10)

这是Java Solution

这是一个经典的Back跟踪问题,用于查找作为输入的整数数组或集合的所有可能子集,然后filtering求和的target总和为import java.util.HashSet; import java.util.StringTokenizer; /** * Created by anirudh on 12/5/15. */ public class findSubsetsThatSumToATarget { /** * The collection for storing the unique sets that sum to a target. */ private static HashSet<String> allSubsets = new HashSet<>(); /** * The String token */ private static final String token = " "; /** * The method for finding the subsets that sum to a target. * * @param input The input array to be processed for subset with particular sum * @param target The target sum we are looking for * @param ramp The Temporary String to be beefed up during recursive iterations(By default value an empty String) * @param index The index used to traverse the array during recursive calls */ public static void findTargetSumSubsets(int[] input, int target, String ramp, int index) { if(index > (input.length - 1)) { if(getSum(ramp) == target) { allSubsets.add(ramp); } return; } //First recursive call going ahead selecting the int at the currenct index value findTargetSumSubsets(input, target, ramp + input[index] + token, index + 1); //Second recursive call going ahead WITHOUT selecting the int at the currenct index value findTargetSumSubsets(input, target, ramp, index + 1); } /** * A helper Method for calculating the sum from a string of integers * * @param intString the string subset * @return the sum of the string subset */ private static int getSum(String intString) { int sum = 0; StringTokenizer sTokens = new StringTokenizer(intString, token); while (sTokens.hasMoreElements()) { sum += Integer.parseInt((String) sTokens.nextElement()); } return sum; } /** * Cracking it down here : ) * * @param args command line arguments. */ public static void main(String[] args) { int [] n = {24, 1, 15, 3, 4, 15, 3}; int counter = 1; FindSubsetsThatSumToATarget.findTargetSumSubsets(n, 25, "", 0); for (String str: allSubsets) { System.out.println(counter + ") " + str); counter++; } } }

25

它给出了与目标相加的子集的空格分隔值。

将打印出总和为{24, 1, 15, 3, 4, 15, 3}的子集的commma分隔值 assert

  

1)24 1

     

2)3 4 15 3

     

3)15 3 4 3

答案 3 :(得分:6)

同一网站geeksforgeeks还讨论了输出总和为特定值的所有子集的解决方案:http://www.geeksforgeeks.org/backttracking-set-4-subset-sum/

在您的情况下,您只需要计算它们,而不是输出集。请务必在同一页面中检查优化版本,因为它是NP-complete问题。

这个问题之前也曾在stackoverflow中被提出并回答,但未提及它是一个子集和问题: Finding all possible combinations of numbers to reach a given sum

答案 4 :(得分:5)

这是我在ruby中的程序。它将返回数组,每个数组保持子序列求和到提供的目标值。

array = [1, 3, 4, 2, 7, 8, 9]

0..array.size.times.each do |i| 
  @ary.combination(i).to_a.each { |a| print a if a.inject(:+) == 9} 
end

答案 5 :(得分:4)

我用java解决了这个问题。这个解决方案很简单。

import java.util.*;

public class Recursion {

static void sum(int[] arr, int i, int sum, int target, String s)
{   
    for(int j = i+1; j<arr.length; j++){
        if(sum+arr[j] == target){
            System.out.println(s+" "+String.valueOf(arr[j]));
        }else{
            sum(arr, j, sum+arr[j], target, s+" "+String.valueOf(arr[j]));
        }
    }
}

public static void main(String[] args)
{   
    int[] numbers = {6,3,8,10,1};
    for(int i =0; i<numbers.length; i++){
        sum(numbers, i, numbers[i], 18, String.valueOf(numbers[i])); 
    }

}
}

答案 6 :(得分:2)

通常的DP解决方案适用于该问题。

您可以做的一个优化是,计算特定总和存在多少解,而不是构成该总和的实际集合...

答案 7 :(得分:2)

这是我在JS中的动态编程实现。它将返回一个数组数组,每个数组都保存与提供的目标值相加的子序列。

-- phpMyAdmin SQL Dump
-- version 4.0.9deb1.lucid~ppa.1
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Mar 30, 2017 at 01:31 PM
-- Server version: 5.5.52-0ubuntu0.12.04.1-log
-- PHP Version: 5.3.10-1ubuntu3.25

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Database: `NULL` 
--

-- --------------------------------------------------------

--
-- Table structure for table `Employer`
--

CREATE TABLE IF NOT EXISTS `Employer` (
  `EmployerID` int(60) NOT NULL,
  `CompName` varchar(60) NOT NULL,
  `Address` varchar(20) NOT NULL,
  `Phone` int(10) NOT NULL,
  `Email` varchar(30) NOT NULL,
  `PosTitle` varchar(30) NOT NULL,
  `Description` varchar(100) NOT NULL,
  `Location` varchar(35) NOT NULL,
  `Skill1` varchar(20) NOT NULL,
  `Experience1` int(10) NOT NULL,
  `Skill2` varchar(20) NOT NULL,
  `Experience2` int(11) NOT NULL,
  `Skill3` varchar(20) NOT NULL,
  `Experience3` int(11) NOT NULL,
  `Need` varchar(15) NOT NULL,
  PRIMARY KEY (`EmployerID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Dumping data for table `Employer`
--

INSERT INTO `Employer` (`EmployerID`, `CompName`, `Address`, `Phone`, `Email`, `PosTitle`, `Description`, `Location`, `Skill1`, `Experience1`, `Skill2`, `Experience2`, `Skill3`, `Experience3`, `Need`) VALUES
(0, '', '', 0, '', '', '', '', '', 0, '', 0, '', 0, '');

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */

;

答案 8 :(得分:0)

Python function subset that return subset of list that adds up to a particular value

def subset(ln, tar):#ln=Lenght Of String, tar= Target
s=[ int(input('Insert Numeric Value Into List:')) for i in range(ln) ]#Inserting int Values in s of type<list>
if sum(s) < tar:#Sum of List is less than Target Value
    return
elif sum(s) == tar:#Sum of list is equal to Target Value i.e for all values combinations
    return s
elif tar in s:#Target value present in List i.e for single value
    return s[s.index(tar)]
else:#For remaining possibilities i.e for all except( single and all values combinations )
    from itertools import combinations# To check all combinations ==> itertools.combinations(list,r) OR return list of all subsets of length r
    r=[i+1 for i in range(1,ln-1)]# Taking r as only remaining value combinations, i.e. 
                                 # Except(  r=1 => for single value combinations AND r=length(list) || r=ln => For all value combinations
    lst=list()#For Storing all remaining combinations
    for i in range(len(r)):
        lst.extend(list( combinations(s,r[i]) ))
    for i in range(len(lst)):# To check remaining possibilities
        if tar == sum(lst[i]):
            return list(lst[i])

subset(int(input('列表长度:')),int(input('Target:')))

答案 9 :(得分:0)

我发现有这么多面试都要求这样做,所以我实现了一个非常简单易懂的解决方案。首先,我生成所有可能的组合,然后,您可以执行所需的任何操作。检查一下:

public static void main(String[] args) {
        int[] numbers = new int[]{1, 2, 3, 4, 5};
        List<int[]> allPossibleCombinatiosForNumbers = new ArrayList<>();
        for (int i = 2; i < numbers.length; i++) {
            allPossibleCombinatiosForNumbers.addAll(getCombinationsOfNElements(numbers, i));
        }
        for (int[] combination : allPossibleCombinatiosForNumbers) {
            printArray(combination);
            printArrayIfNumbersSumExpectedValue(combination, 6);
        }
    }


    private static List<int[]> getCombinationsOfNElements(int[] numbers, int n) {
        int elementsKnown = n - 1;
        List<int[]> allCombinationsOfNElements = new ArrayList<>();
        for (int i = 0; i < numbers.length - elementsKnown; i++) {
            int[] combination = new int[n];
            for (int j = 0; j < n; j++) {
                combination[j] = numbers[i + j];
            }
            allCombinationsOfNElements.addAll(generationCombinations(combination, i + elementsKnown, numbers));
        }
        return allCombinationsOfNElements;
    }

    private static List<int[]> generationCombinations(int[] knownElements, int index, int[] numbers) {
        List<int[]> combinations = new ArrayList<>();
        for (int i = index; i < numbers.length; i++) {
            int[] combinationComplete = Arrays.copyOf(knownElements, knownElements.length);
            combinationComplete[knownElements.length - 1] = numbers[i];
            combinations.add(combinationComplete);
        }
        return combinations;
    }

    private static void printArray(int[] numbers) {
        System.out.println();
        for (int i = 0; i < numbers.length; i++) {
            System.out.print(numbers[i] + " ");
        }
    }

    private static void printArrayIfNumbersSumExpectedValue(int[] numbers, int expectedValue) {
        int total = 0;
        for (int i = 0; i < numbers.length; i++) {
            total += numbers[i];
        }
        if (total == expectedValue) {
            System.out.print("\n ----- Here is a combination you are looking for -----");
            printArray(numbers);
            System.out.print("\n -------------------------------");
        }
    }

答案 10 :(得分:0)

我使用“动态编程和记忆化”从具有特定总数的集合中找到子集的数量。下面的代码在Java中。包含注释以解释代码意图-

package com.company.dynamicProgramming;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class FindSumInSubSet {

    public static void main(String...args){

        int[] arr = {3, 2, 4, 6, 10};
        int total = 16;
        // Challenge is to find the subsets of numbers total 6 in above super set (represented as array)
        // In general - Write a code to count subset of elements totalling m(6 above) in given set of n(9 as array size above) elements

        Map<Entry, Integer> memoMap = new HashMap<>();

        Entry entry = new Entry(total, arr.length-1);

        int count = countSubSetForSum(arr, entry, memoMap);
        System.out.format("In set of %d elements, the number of subsets having total=%d is %d %n", arr.length,total, count);
    }


    static int countSubSetForSum(int[] arr, Entry entry, Map<Entry, Integer> memoMap){

        int total = entry.getTotal();
        int i = entry.getI();

        if (total == 0){             // means element was equal in previous recursion
            return 1;
        }else if(total < 0){         // means element was less in previous recursion i.e. not equal
            return 0;
        }else if (i < 0){            // means arr was finished previous recursion
            return 0;
        }else if (arr[i] > total){   // means element is greater than total
                                     // i.e. leave that element and look further sets excluding this element
            return getCountForIthAndTotal(arr, new Entry( total, i-1), memoMap);

        }else{                       // means element is less than total i.e. 2 possibilities :
                                     // 1st - look further sets including this element
                                     // 2nd - look further sets excluding this element
            return getCountForIthAndTotal(arr, new Entry( total-arr[i], i-1), memoMap) +
                    getCountForIthAndTotal(arr, new Entry( total, i-1), memoMap);
        }
    }


    static int getCountForIthAndTotal(int[] arr, Entry entry, Map<Entry, Integer> memoMap){
        if (memoMap.containsKey(entry)){     //look up in has table if we already calculated particular total for ith subset..
            return memoMap.get(entry);       //This is nothing but using memoization that reduce the entire below code i.e. further recursion -
        }else {
            int count = countSubSetForSum(arr, entry, memoMap);  //Recursion
            memoMap.put(entry, count); //Build memoization
            return count;
        }
    }


    //Just Data Structure for Key in HashMap (memoMaP)... intent to include particular total for ith element's subset.
    static class Entry {
        int total;
        int i;

        public Entry(int total, int i) {
            this.total = total;
            this.i = i;
        }

        public int getTotal() {
            return total;
        }

        public int getI() {
            return i;
        }


        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Entry entry = (Entry) o;
            return total == entry.total &&
                    i == entry.i;
        }

        @Override
        public int hashCode() {
            return Objects.hash(total, i);
        }
    }

}

当我运行此输出时:

In set of 5 elements, the number of subsets having total=16 is 2 
Process finished with exit code 0

答案 11 :(得分:0)

当输入量很大(即25到30)时,这是一种有效的解决方案

我通过两种方式提高了效率:

  • 利用简单的滚轮概念在所有可能的迭代中进行二进制计数,而不是使用数学上昂贵的基本转换语言功能。该“轮子”类似于旧的机械计数器或里程表。它会递归地根据需要滚动到多个位置,直到我们超过所拥有的二进制数字的数量(例如,集合中的数字计数)。
  • 主要好处是每次都不求和整个候选集。取而代之的是,它保持运行总和,并且每次“滚动”时,它仅针对与测试的最后一个候选集相比发生变化的零件调整运行总和。由于大多数“滚轮”仅更改一个或两个数字,因此可以节省大量计算。

此解决方案适用于负数,十进制数和重复的输入值。由于浮点十进制数学在大多数语言中都适用,所以您可能希望将输入设置为仅保留几个小数位,否则可能会有一些不可预测的行为。

在旧的2012年以前的台式机上,给定的代码在javascript / node.js中大约 0.8秒和C#中在 3.4秒中处理了25个输入值。 / p>

javascript

let numbers = [-0.47, -0.35, -0.19, 0.23, 0.36, 0.47, 0.51, 0.59, 0.63, 0.79, 0.85, 
0.91, 0.99, 1.02, 1.17, 1.25, 1.39, 1.44, 1.59, 1.60, 1.79, 1.88, 1.99, 2.14, 2.31];

let target = 24.16;

displaySubsetsThatSumTo(target, numbers);

function displaySubsetsThatSumTo(target, numbers)
{
    let wheel = [0];
    let resultsCount = 0;
    let sum = 0;

    const start = new Date();
    do {
        sum = incrementWheel(0, sum, numbers, wheel);
        //Use subtraction comparison due to javascript float imprecision
        if (sum != null && Math.abs(target - sum) < 0.000001) {
            //Found a subset. Display the result.
            console.log(numbers.filter(function(num, index) {
                return wheel[index] === 1;
            }).join(' + ') + ' = ' + target);
            resultsCount++;
        }
    } while (sum != null);
    const end = new Date();

    console.log('--------------------------');
    console.log(`Processed ${numbers.length} numbers in ${(end - start) / 1000} seconds (${resultsCount} results)`);
}

function incrementWheel(position, sum, numbers, wheel) {
    if (position === numbers.length || sum === null) {
        return null;
    }
    wheel[position]++;
    if (wheel[position] === 2) {
        wheel[position] = 0;
        sum -= numbers[position];
        if (wheel.length < position + 2) {
            wheel.push(0);
        }
        sum = incrementWheel(position + 1, sum, numbers, wheel);
    }
    else {
        sum += numbers[position];
    }
    return sum;
}

C#

    public class Program
    {
        static void Main(string[] args)
        {
            double[] numbers = { -0.47, -0.35, -0.19, 0.23, 0.36, 0.47, 0.51, 0.59, 0.63, 0.79, 0.85,
                0.91, 0.99, 1.02, 1.17, 1.25, 1.39, 1.44, 1.59, 1.60, 1.79, 1.88, 1.99, 2.14, 2.31 };

            double target = 24.16;

            DisplaySubsetsThatSumTo(target, numbers);
        }

        private static void DisplaySubsetsThatSumTo(double Target, double[] numbers)
        {
            var stopwatch = new System.Diagnostics.Stopwatch();

            bool[] wheel = new bool[numbers.Length];
            int resultsCount = 0;
            double? sum = 0;

            stopwatch.Start();

            do
            {
                sum = IncrementWheel(0, sum, numbers, wheel);
                //Use subtraction comparison due to double type imprecision
                if (sum.HasValue && Math.Abs(sum.Value - Target) < 0.000001F)
                {
                    //Found a subset. Display the result.
                    Console.WriteLine(string.Join(" + ", numbers.Where((n, idx) => wheel[idx])) + " = " + Target);
                    resultsCount++;
                }
            } while (sum != null);

            stopwatch.Stop();

            Console.WriteLine("--------------------------");
            Console.WriteLine($"Processed {numbers.Length} numbers in {stopwatch.ElapsedMilliseconds / 1000.0} seconds ({resultsCount} results). Press any key to exit.");
            Console.ReadKey();
        }

        private static double? IncrementWheel(int Position, double? Sum, double[] numbers, bool[] wheel)
        {
            if (Position == numbers.Length || !Sum.HasValue)
            {
                return null;
            }
            wheel[Position] = !wheel[Position];
            if (!wheel[Position])
            {
                Sum -= numbers[Position];
                Sum = IncrementWheel(Position + 1, Sum, numbers, wheel);
            }
            else
            {
                Sum += numbers[Position];
            }
            return Sum;
        }
    }

输出

-0.35 + 0.23 + 0.36 + 0.47 + 0.51 + 0.59 + 0.63 + 0.79 + 0.85 + 0.91 + 0.99 + 1.02 + 1.17 + 1.25 + 1.44 + 1.59 + 1.6 + 1.79 + 1.88 + 1.99 + 2.14 + 2.31 = 24.16
0.23 + 0.51 + 0.59 + 0.63 + 0.79 + 0.85 + 0.99 + 1.02 + 1.17 + 1.25 + 1.39 + 1.44 + 1.59 + 1.6 + 1.79 + 1.88 + 1.99 + 2.14 + 2.31 = 24.16
-0.47 + 0.23 + 0.47 + 0.51 + 0.59 + 0.63 + 0.79 + 0.85 + 0.99 + 1.02 + 1.17 + 1.25 + 1.39 + 1.44 + 1.59 + 1.6 + 1.79 + 1.88 + 1.99 + 2.14 + 2.31 = 24.16
-0.19 + 0.36 + 0.51 + 0.59 + 0.63 + 0.79 + 0.91 + 0.99 + 1.02 + 1.17 + 1.25 + 1.39 + 1.44 + 1.59 + 1.6 + 1.79 + 1.88 + 1.99 + 2.14 + 2.31 = 24.16
-0.47 + -0.19 + 0.36 + 0.47 + 0.51 + 0.59 + 0.63 + 0.79 + 0.91 + 0.99 + 1.02 + 1.17 + 1.25 + 1.39 + 1.44 + 1.59 + 1.6 + 1.79 + 1.88 + 1.99 + 2.14 + 2.31 = 24.16
0.23 + 0.47 + 0.51 + 0.63 + 0.85 + 0.91 + 0.99 + 1.02 + 1.17 + 1.25 + 1.39 + 1.44 + 1.59 + 1.6 + 1.79 + 1.88 + 1.99 + 2.14 + 2.31 = 24.16
--------------------------
Processed 25 numbers in 0.823 seconds (6 results)

答案 12 :(得分:0)

以下解决方案还提供了提供特定总和(此处总和= 9)的子集数组

array = [1, 3, 4, 2, 7, 8, 9]

(0..array.size).map { |i| array.combination(i).to_a.select { |a| a.sum == 9 } }.flatten(1)

返回子集的数组,返回9的总和

 => [[9], [1, 8], [2, 7], [3, 4, 2]] 

答案 13 :(得分:0)

子集总和问题可以使用动态编程在 O(sum * n)中解决。子集总和的最佳子结构如下:

SubsetSum(A,n,sum)= SubsetSum(A,n-1,sum)|| SubsetSum(A,n-1,sum-set [n-1])

SubsumSum(A,n,sum)= 0,如果sum> 0并且n == 0 SubsumSum(A,n,sum)= 1,如果sum == 0

此处 A 是元素数组, n 是数组A的元素数, sum 是子集中的元素之和

使用此dp,您可以求出总和的子集数。

要获取子集元素,我们可以使用以下算法:

通过调用SubsetSum(A,n,sum)填充 dp [n] [sum] 后,我们从dp [n] [sum]递归遍历它。对于正在遍历的单元格,我们在到达之前存储路径,并考虑该元素的两种可能性。

1)元素包含在当前路径中。

2)当前路径中不包含元素。

只要sum变为0,我们就会停止递归调用并显示当前路径。

void findAllSubsets(int dp[], int A[], int i, int sum, vector<int>& p) { 

   if (sum == 0) { 
        print(p); 
        return; 
   } 

   // If sum can be formed without including current element
   if (dp[i-1][sum]) 
   { 
        // Create a new vector to store new subset 
        vector<int> b = p; 
        findAllSubsets(dp, A, i-1, sum, b); 
   } 

   // If given sum can be formed after including 
   // current element. 
   if (sum >= A[i] && dp[i-1][sum-A[i]]) 
   { 
        p.push_back(A[i]); 
        findAllSubsets(dp, A, i-1, sum-A[i], p); 
   } 

} 

答案 14 :(得分:0)

虽然很容易找到它们是否是目标的一个子集,但是当您需要跟踪所考虑的部分子集时,实现就会变得棘手。

如果您使用链表,哈希集或任何其他通用集合,则很容易在包含该项目的调用之前将一个项目添加到此集合中,然后在排除该项目的调用之前将其删除。这不能按预期方式工作,因为将要添加的堆栈帧与将要发生删除的堆栈帧不同。

解决方案是使用字符串来跟踪序列。可以在函数调用中内联添加到字符串;从而保持相同的堆栈框架,您的答案将与原始的hasSubSetSum递归结构完美地吻合。

import java.util.ArrayList;

公共类解决方案{

public static boolean hasSubSet(int [] A, int target) {
    ArrayList<String> subsets = new ArrayList<>();
    helper(A, target, 0, 0, subsets, "");
    // Printing the contents of subsets is straightforward
    return !subsets.isEmpty();
}

private static void helper(int[] A, int target, int sumSoFar, int i, ArrayList<String> subsets, String curr) {
    if(i == A.length) {
        if(sumSoFar == target) {
            subsets.add(curr);
        }
        return;
    }
    helper(A, target, sumSoFar, i+1, subsets, curr);
    helper(A, target, sumSoFar + A[i], i+1, subsets, curr + A[i]);
}

public static void main(String [] args) {
    System.out.println(hasSubSet(new int[] {1,2,4,5,6}, 8));
}

}

答案 15 :(得分:0)

我的回溯解决方案: - 对数组进行排序,然后应用回溯。

void _find(int arr[],int end,vector<int> &v,int start,int target){
        if(target==0){
        for(int i = 0;i<v.size();i++){
            cout<<v[i]<<" ";
        }
        cout<<endl;
    }

    else{
        for(int i =  start;i<=end && target >= arr[i];i++){
            v.push_back(arr[i]);
            _find(arr,end,v,i+1,target-arr[i]);
            v.pop_back();
        }
    }
}

答案 16 :(得分:0)

<强> RUBY

此代码将拒绝空数组并返回带有值的正确数组。

def find_sequence(val, num)
  b = val.length
  (0..b - 1).map {|n| val.uniq.combination(n).each.find_all {|value| value.reduce(:+) == num}}.reject(&:empty?)
end

val = [-10, 1, -1, 2, 0]
num = 2

输出将是[[2],[2,0],[ - 1,1,2],[ - 1,1,2,0]]

答案 17 :(得分:0)

public class SumOfSubSet {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        int a[] = {1,2};
        int sum=0;
        if(a.length<=0) {
            System.out.println(sum);
        }else {
        for(int i=0;i<a.length;i++) {
            sum=sum+a[i];
            for(int j=i+1;j<a.length;j++) {
                sum=sum+a[i]+a[j];
            }
        }
        System.out.println(sum);

        }


    }

}