找到给定数组大小的给定数字的所有组合

时间:2016-05-25 12:30:35

标签: java arrays combinations

我需要找到大小为n的所有组合,其中包含数字数组中的数字。我试着用我下面写的函数来做这件事,但这需要花费很多时间和内存。

有没有办法提高效率?

void createCombinationArray(ArrayList<Integer> numbers, int n, ArrayList<Integer> start) {
    if (start.size() >= n) {
        monthsComb.add(new ArrayList<>(start));
    } else {
        for (Integer x : numbers) {
            start.add(x);
            createCombinationArray(numbers, n, start);
            start.remove(start.lastIndexOf(x));
        }
    }
}

3 个答案:

答案 0 :(得分:0)

问问自己是否真的需要提前生成所有这些列表。也许按需生成它们是可以接受的。

请注意,这些列表中的每一个都可以使用numbers.length位,n或更多位设置的数字来表示。您可以使用此类数据结构来引用其外部列表。

使用此行为编写List实现将非常简单。

import java.util.BitSet;
import java.util.List;

public class SelectiveList<T> implements List<T> {
    private final BitSet bitSet;
    private final List<T> list;

    public SelectiveList(BitSet bitSet, List<T> list) {
        this.bitSet = bitSet;
        this.list = list;
    }

    @Override
    public T get(int index) {
        return list.get(nthOnBit(index));
    }

    private int nthOnBit(int n) {
        int onBits = 0;
        int i;
        for (i = bitSet.nextSetBit(0); i >= 0 && onBits < n; i = bitSet.nextSetBit(i + 1)) {
            onBits++;
        }
        if (onBits < n) {
            throw new IllegalArgumentException();
        }

        return i;
    }

    // etc.
}

答案 1 :(得分:0)

更有效(时间和内存)的一种方法是将结果存储为int[][]而不是Collection<List<Integer>>(我假设它是monthsComb的类型领域)。你可以这样做,因为你知道如果你有k个数字,那么结果将是n个数字的Binomial(n, k)组合。

另一种方式(如@ Phia-CM建议的那样)将实现算法的非复数版本。

我知道他们都不愿意实施,但这是提高效率的方法。

答案 2 :(得分:0)

你可以试试这个:

package combination;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Combination implements Iterator<List<Integer>> {

    public Combination(final List<Integer> numbers, final int n) {
        this.numbers = numbers;
        this.n = n;
        this.current = BigInteger.valueOf(0);
        this.radix = BigInteger.valueOf(numbers.size());
        this.size = this.radix.pow(n);
    }

    @Override
    public final boolean hasNext() {
        return this.current.compareTo(size) < 0;
    }

    @Override
    public final List<Integer> next() {
        List<Integer> result = new ArrayList(this.n);
        BigInteger value = this.current;
        for(int i=0; i<n; i++) {
            result.add(i, this.numbers.get(
                    value.mod(this.radix).intValueExact()));
            value = value.divide(this.radix);
        }
        this.current = this.current.add(BigInteger.valueOf(1));
        return result;
    }

    private final List<Integer> numbers;
    private final int n;
    private BigInteger current; 
    private final BigInteger size;
    private final BigInteger radix;

    public static void main(String[] args) {
        Combination cb = new Combination(Arrays.asList(0, 2, 4, 6), 3);
        while (cb.hasNext()) {
            System.out.println(cb.next());
        }
    }
}