给出一个大的1-d数组。 为了节省大数组的内存,我需要在循环中获得下一个k组合(组合学中的C(n,k)),懒惰。
由于问题不小,我很难实施。
这是我正在尝试做的伪代码:
public void doSomething(int[] array, int k) {
for(current combinations in combinations(i, k)) {
... // do something
}
...
}
更新 请参阅下面的解决方案。
答案 0 :(得分:0)
我在C ++中做了类似的事情。我所做的是实现一个迭代器,它将系统生成的组合序列中的迭代位置作为其状态信息。递增迭代器会更改状态信息以指示下一个组合。取消引用迭代器计算序列中当前位置的组合。
答案 1 :(得分:0)
我假设问题被赋予一组值{x1,x2,x3,...,xn}生成{xi,xii,xiii,...,xk}的所有可能值。这是一个难以编程的问题......但是模式非常简单。我假设所有{x1,x2,x3,... xn}都是不同的(否则它会更难)。假设所有xn都是不同的,那么有一个非常简单的模式来生成所有可能的k = 2集:
public class Set{
private final int[] set;
public Set(final int ...set){
this.set = new int[set.length];
for(int i = 0; i < set.length; ++i)
this.set[i] = set[i];
}
}
如果您知道您想要多少组合,那么找到该组合的组合很简单,这里是一个例子:
public int[][] get2Comb(final int[] set){
int combIndex = 0;
final int[][] comb = new int[comb2(set.length)][2];
for(int i = 0; i < set.length - 1; ++i)
for(int j = i + 1; j < set.length; ++j){
comb[combIndex][0] = i;
comnb[combIndex++][1] = j;
}
return comb;
}
对于k = 3的设置,它必须如下所示:
public int[][] get3Comb(final int[] set){
int combIndex = 0;
final int[][] comb = new int[comb3(set.length)][3];
for(int i = 0; i < set.length - 2; ++i)
for(int j = i + 1; j < set.length - 1; ++j)
for(k = j + 1; k < set.length; ++k)
comb[combIndex][0] = i;
comb[combIndex][1] = j;
comnb[combIndex++][2] = k;
}
return comb;
}
你看到它显然是recurses ...我发现不太可能存在迭代方案(尽管技术上总是存在)。我曾经遇到过像这样的问题,我的解决方案是生成代码而不是试图找出递归解决方案(我怀疑应该存在)。 Java反射当然是一个想法,但这基本上是生成代码 - 所以应该有一个更好的解决方案。
答案 2 :(得分:-1)
我在Groovy中实现了一个懒惰的迭代器,它不需要额外的内存或初步计算(只有长度为k的数组用于跟踪索引,这些索引的长度通常非常小)。 如果愿意,您可以轻松地将其转换为Java代码。
Lazy Iterator用于选择所有C(n,k)组合:
import sun.reflect.generics.reflectiveObjects.NotImplementedException
class Combinations implements Iterator {
int[] indices
def itemset
def choose
boolean hasNext = true
Combinations(def itemset, int choose) {
this.choose = choose
this.itemset = itemset
//Initialize indices
indices = new int[choose]
for (i in 0..<choose) {
indices[i] = i
}
}
private def prepareNext() {
int rightMostIndex = { /* Closure to find the right-most index */
for (i in choose-1..0){
int bounds = itemset.size() - choose + i
if (indices[i] < bounds) return i
}
return -1
}() // execute closure
// increment all indices
if (rightMostIndex >= 0) {
indices[rightMostIndex]++
for (i in rightMostIndex+1..<choose) {
indices[i] = indices[i-1] + 1;
}
// there are still more combinations
hasNext = true
return
}
// reached the end, no more combinations
hasNext = false
}
@Override
boolean hasNext() {
return hasNext
}
@Override
def next() {
if (!hasNext)
throw new NoSuchElementException();
def combination = []
for (i in 0..<indices.size()) {
combination << itemset[indices[i]]
}
prepareNext()
return combination
}
@Override
public void remove() {
throw new NotImplementedException()
}
}
用法示例:
def c = new Combinations([1, 2, 3], 2)
for (e in c) {
println e
}
<强>输出:强>
[1, 2]
[1, 3]
[2, 3]