Algorithm 组合问题

Algorithm 组合问题,algorithm,combinations,combinatorics,Algorithm,Combinations,Combinatorics,我认为这是一个枚举组合问题 我需要从15个重复元素中选择7个元素,我想知道是否有一种简单的方法可以将所有组合存储在一个数组中,并直接找到我感兴趣的元素 基本上,我正在构建一个大的查找表,其中包含一个非常昂贵的计算值,我想知道我是否可以使用一个简单的公式访问它。注意,这不是家庭作业,请检查我的配置文件 15个中有7个重复的组合数量为116 280,我仔细检查了是否正确 代码如下: public static void main(String[] args) { final Random r

我认为这是一个枚举组合问题

我需要从15个重复元素中选择7个元素,我想知道是否有一种简单的方法可以将所有组合存储在一个数组中,并直接找到我感兴趣的元素

基本上,我正在构建一个大的查找表,其中包含一个非常昂贵的计算值,我想知道我是否可以使用一个简单的公式访问它。注意,这不是家庭作业,请检查我的配置文件

15个中有7个重复的组合数量为116 280,我仔细检查了是否正确

代码如下:

public static void main(String[] args) {
    final Random r = new Random( System.currentTimeMillis() );
    final List<String> ls = new ArrayList<String>();
    for (int i = 0; i < 15; i++) {
        for (int j = i; j < 15; j++) {
            for (int k = j; k < 15; k++) {
                for (int l = k; l < 15; l++) {
                    for (int m = l; m < 15; m++) {
                        for (int n = m; n < 15; n++) {
                            for (int o = n; o < 15; o++) {
                                ls.add( i + " " + j + " " + k + " " + l + " " + m + " " + n + " " + o + ": " + r.nextLong() );
                            }
                        }
                    }
                }
            }
        }
    }
    System.out.println( "We have " + ls.size() + " entries" );
    System.out.println( "Entry @ 5,7,2,10,11,8,3 is " + getEntryAt(5,7,2,10,11,8,3) );
}

private static String getEntryAt( int i, int j, int k, int l, int m, int n, int o ) {
    return "FILL ME"; // What goes here ?
}
在上面的例子中,我只是在查找数组中放入一个随机值,但基本上就是这样:我想得到,比如说,5,7,2,10,11,8,3,我能很容易地计算出它的位置吗

请注意,我在数组中存储元素的方式并不重要:我可以使用最快的公式(如果有的话)来存储它们

如果有人知道我在说什么,欢迎提供任何帮助。

似乎您需要一个映射,其中T是计算值的类型。HashMap会在内部使用数组,所以我想这是一个有效的答案

使密钥为多集的点是多集上的等值方法应该考虑两个多集相等,如果它们包含相同数量的每个元素,则不考虑排序。顺便说一下,JDK没有Multiset类,但是您可以找到第三方Multiset类

long[,,,,,,] ls = new long[15, 15, 15, 15, 15, 15, 15];
在深度嵌套的for循环中:

ls[i, j, k, l, m, n, o] = r.nextLong();
对于get语句,它非常简单:

return ls[i, j, k, l, m, n, o];

但是对于这一点,ls需要作为参数传递给getter函数,或者它需要是全局的。

分解它的简单方法是将计数作为部分求和。在我的示例中,我使用了基于1的索引

假设给你的数字更少,但元组2,3,4的原理是一样的。其位置仅为以下各项之和:

1,x,y-所有符合此条件的数字 2,2,x 2,3,x-其中x<4 你可以迭代地解决这个问题

现在,对于D=3位和K项,您可以绘制图案并查看其增长情况:

K = 1

1 1 1

K = 2

1 1 1
1 1 2

1 2 2

2 2 2

K = 3

1 1 1
1 1 2
1 1 3

1 2 2
1 2 3

1 3 3

2 2 2
2 2 3

2 3 3

3 3 3
对于每一次迭代,您实际上要做的是将前面的分组包括一个空分组,并添加一个额外的数字,就像三角形数字序列一样。当你增加第一个数字时,你甚至可以递归地想到这一点——在上面的D=3,K=3的例子中,你可以重新映射不以1开头的东西的符号,因此它们不包含任何1——D仍然是3,但K现在是2:

K = 3 (ignoring 1's)

2 2 2
2 2 3

2 3 3

3 3 3
变成:

K = 2

1 1 1
1 1 2

1 2 2

2 2 2
这就是如何添加到K中的方法。对于D=3,请注意它们是三角形数字

加一个数字怎么样?对于K=3,D=3,你可以想象,假设:

K = 3

1 1 1
1 1 2
1 1 3

1 2 2
1 2 3

1 3 3

2 2 2
2 2 3

2 3 3

3 3 3
并在其前面添加一个数字。您可以在它们前面添加1。您只能在2或更高版本前面添加2,在只有3的版本前面添加3。现在您可以看到递归结构

举一个简单的例子,要找到D=3,K=5的2,4,4的索引:

index( 2, 4, 4 ) =
   # number of leading 1's, and re-index
   index( 3, 3 ) + count( D = 2, K = 5 ) =
   index( 3, 3 ) + 15 =
   # number of leading 1's and 2's, and re-index
   index( 1 ) + count( D = 1, K = 4 ) + count( D = 1, K = 3 ) + 15 =
   index( 1 ) + 4 + 3 + 15 = index( 1 ) + 22 = 
   22
所以指数2,4,4=22

现在棘手的部分是计算出D,K,实际上就是ck+D-1,D。现在可以把它推广到K=15,D=7

// This is actually 0-based.
// Really should use an array or something to make it easy to generalize, 
// so I'm going to skip a lot of cut and paste
private static int getEntryAt( int i, int j, int k, int l, int m, int n, int o ) {
   int D = 7, K = 15;
   int total = 0;

   if ( i > 0 ) {
      for ( int index = 0; index < i; index++ ) {
         total += count( D, K - index );
      }
   }

   j -= i, k -= i, l -= i, m -= i, n -= i, o -= i;
   D--;
   K -= i;
   // repeat for j, k, ...

   return count;
}

建造一棵7米高的树。根节点有15个子节点,命名为1-15。每个子名称对应于集合中该数字的选择。编号为n的节点有编号为m n的子节点也许您可以用它来解决您的问题?

不确定我是否在跟踪,您究竟在寻找什么?您的示例5,7,2,10,11,8,3的“位置”是什么以及预期输出是什么?您是否可以使用所有7个数字作为值的索引来构建多维数组?您的列表是否应该按顺序排列,例如{11,10,8,7,5,3,2}?否则,您不是在处理排列而不是组合吗?@mbeckish:但是,您有一个15 exp 7左右的数组,它需要1.7亿个左右的条目,而在本例中,重复的组合数只有116 820,这只是一个示例。@Mr.Wizard:“查询”的顺序并不重要,如果需要,可以对其进行简单的规范化。例如{11,10,8,7,5,3,2}必须使用与{11,7,3,10,8,5,2}相同的结果。这真的只是一个例子:+1,非常感谢你花时间写这篇文章。这应该让我开始:很好的答案+1:我可能对你的伪代码表示法不太熟悉,但你不是在提倡创建一个15 exp 7数组,这将是1.7亿个条目,只是为了保存一个与重复的组合,而对于15和7,yelds只有116 820个结果吗?@SyntaxT3rr0r所有的代码表示法实际上都是完全合法的c。至于明显的判断错误,我没有意识到你的问题集可能导致的简化,因此我同意在重复次数太多时使用简单数组会减少记忆意识。但另一方面,数组是递增的 速度非常快,如果内存不是您更关心的问题,那么如果您有足够的内存来保存所有数据,那么简单编写数组的方法可能比复杂的解决方案更好,可以节省少量内存。