Algorithm 组合问题
我认为这是一个枚举组合问题 我需要从15个重复元素中选择7个元素,我想知道是否有一种简单的方法可以将所有组合存储在一个数组中,并直接找到我感兴趣的元素 基本上,我正在构建一个大的查找表,其中包含一个非常昂贵的计算值,我想知道我是否可以使用一个简单的公式访问它。注意,这不是家庭作业,请检查我的配置文件 15个中有7个重复的组合数量为116 280,我仔细检查了是否正确 代码如下:Algorithm 组合问题,algorithm,combinations,combinatorics,Algorithm,Combinations,Combinatorics,我认为这是一个枚举组合问题 我需要从15个重复元素中选择7个元素,我想知道是否有一种简单的方法可以将所有组合存储在一个数组中,并直接找到我感兴趣的元素 基本上,我正在构建一个大的查找表,其中包含一个非常昂贵的计算值,我想知道我是否可以使用一个简单的公式访问它。注意,这不是家庭作业,请检查我的配置文件 15个中有7个重复的组合数量为116 280,我仔细检查了是否正确 代码如下: public static void main(String[] args) { final Random r
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。至于明显的判断错误,我没有意识到你的问题集可能导致的简化,因此我同意在重复次数太多时使用简单数组会减少记忆意识。但另一方面,数组是递增的 速度非常快,如果内存不是您更关心的问题,那么如果您有足够的内存来保存所有数据,那么简单编写数组的方法可能比复杂的解决方案更好,可以节省少量内存。