我需要找到大小为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));
}
}
}
答案 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());
}
}
}