Finding all possible combinations of numbers to reach a given sum

前端 未结 30 3029
一个人的身影
一个人的身影 2020-11-21 06:39

How would you go about testing all possible combinations of additions from a given set N of numbers so they add up to a given final number?

A brief exam

30条回答
  •  清酒与你
    2020-11-21 07:16

    Here is a Java version which is well suited for small N and very large target sum, when complexity O(t*N) (the dynamic solution) is greater than the exponential algorithm. My version uses a meet in the middle attack, along with a little bit shifting in order to reduce the complexity from the classic naive O(n*2^n) to O(2^(n/2)).

    If you want to use this for sets with between 32 and 64 elements, you should change the int which represents the current subset in the step function to a long although performance will obviously drastically decrease as the set size increases. If you want to use this for a set with odd number of elements, you should add a 0 to the set to make it even numbered.

    import java.util.ArrayList;
    import java.util.List;
    
    public class SubsetSumMiddleAttack {
        static final int target = 100000000;
        static final int[] set = new int[]{ ... };
    
        static List evens = new ArrayList<>();
        static List odds = new ArrayList<>();
    
        static int[][] split(int[] superSet) {
            int[][] ret = new int[2][superSet.length / 2]; 
    
            for (int i = 0; i < superSet.length; i++) ret[i % 2][i / 2] = superSet[i];
    
            return ret;
        }
    
        static void step(int[] superSet, List accumulator, int subset, int sum, int counter) {
            accumulator.add(new Subset(subset, sum));
            if (counter != superSet.length) {
                step(superSet, accumulator, subset + (1 << counter), sum + superSet[counter], counter + 1);
                step(superSet, accumulator, subset, sum, counter + 1);
            }
        }
    
        static void printSubset(Subset e, Subset o) {
            String ret = "";
            for (int i = 0; i < 32; i++) {
                if (i % 2 == 0) {
                    if ((1 & (e.subset >> (i / 2))) == 1) ret += " + " + set[i];
                }
                else {
                    if ((1 & (o.subset >> (i / 2))) == 1) ret += " + " + set[i];
                }
            }
            if (ret.startsWith(" ")) ret = ret.substring(3) + " = " + (e.sum + o.sum);
            System.out.println(ret);
        }
    
        public static void main(String[] args) {
            int[][] superSets = split(set);
    
            step(superSets[0], evens, 0,0,0);
            step(superSets[1], odds, 0,0,0);
    
            for (Subset e : evens) {
                for (Subset o : odds) {
                    if (e.sum + o.sum == target) printSubset(e, o);
                }
            }
        }
    }
    
    class Subset {
        int subset;
        int sum;
    
        Subset(int subset, int sum) {
            this.subset = subset;
            this.sum = sum;
        }
    }
    

提交回复
热议问题