Java 懒散地获得n-集的所有k-组合

Java 懒散地获得n-集的所有k-组合,java,combinations,combinatorics,Java,Combinations,Combinatorics,给定一个大的一维数字数组。 为了节省大型数组的内存,我需要循环下一个k-组合(组合数学中的C(n,k)),缓慢地 由于这个问题并不琐碎,我很难实现它 以下是我尝试执行的伪代码: public void doSomething(int[] array, int k) { for(current combinations in combinations(i, k)) { ... // do something } ... } 更新: 请参阅下面的解决方案。 < P>我在C+

给定一个大的一维数字数组。 为了节省大型数组的内存,我需要循环下一个k-组合(组合数学中的C(n,k)),缓慢地

由于这个问题并不琐碎,我很难实现它

以下是我尝试执行的伪代码:

public void doSomething(int[] array, int k) {

  for(current combinations in combinations(i, k)) {
     ... // do something
  }
  ...
}
更新:
请参阅下面的解决方案。

< P>我在C++中做了类似的事情。我所做的是实现一个迭代器,它将迭代在系统生成的组合序列中的位置作为其状态信息。递增迭代器会更改状态信息以指示下一个组合。取消对迭代器的引用计算了序列中当前位置的组合。

我假设问题是给定一组值{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];
    }
}
公共类集合{
私有最终int[]集;
公共集合(最终整数…集合){
this.set=newint[set.length];
对于(int i=0;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;

}
public int[]get2Comb(最终int[]set){
int combinex=0;
最终整数[][]梳=新整数[comb2(集合长度)][2];
对于(int i=0;i
对于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;

}
public int[]get3Comb(最终int[]set){
int combinex=0;
最终整数[][]梳=新整数[comb3(集合长度)][3];
对于(int i=0;i

你看,它显然是递归的……我发现不太可能有一个迭代方案(尽管技术上总是存在一个)。我曾经遇到过这样的问题,我的解决方案是生成代码,而不是试图找出递归解决方案(我怀疑它应该存在)。Java反射当然是一个想法,但这基本上是生成代码——因此应该有一个更好的解决方案。

我在Groovy中实现了一个惰性迭代器,它不需要额外的内存或初步计算(只需要长度k的数组来跟踪大部分非常小的索引)。 如果愿意,您可以轻松地将其转换为java代码

用于选择所有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]
输出:

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]

到目前为止,您尝试了什么?我实现了这一点,以一次获得所有组合,而不是使用k对。而且很难懒散地计算。这不是小事,我不太明白你所说的“为了为大型数组节省内存…”的意思,这些组合使输入变大,而与数组的大小无关,而与数组的长度无关。@Jared我应用递归回溯,需要惰性地计算下一个组合,当没有解决方案时,我会提前回溯。从而节省memory@vibneiro好,你说你需要得到C(n,k)的下一个k-组合。1) 这不允许一个“好”的解决方案,因为组合的每次计算都像n的阶乘,2)你到底想做什么?你需要在你的问题中定义n,k,d的意思。这个主意是什么?你能分享你的代码吗?