Java 懒散地获得n-集的所有k-组合
给定一个大的一维数字数组。 为了节省大型数组的内存,我需要循环下一个k-组合(组合数学中的C(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+
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的意思。这个主意是什么?你能分享你的代码吗?