Eso*_*ack 28 java combinations combinatorics
现在我正在尝试编写一个带有数组和整数n的函数,并给出每个大小为n的组合的列表(所以是int数组的列表).我能够使用n个嵌套循环编写它,但这仅适用于特定大小的子集.我无法弄清楚如何推广它适用于任何大小的组合.我想我需要使用递归?
这是3个元素的所有组合的代码,我需要一个适用于任意数量元素的算法.
import java.util.List;
import java.util.ArrayList;
public class combinatorics{
public static void main(String[] args) {
List<int[]> list = new ArrayList<int[]>();
int[] arr = {1,2,3,4,5};
combinations3(arr,list);
listToString(list);
}
static void combinations3(int[] arr, List<int[]> list){
for(int i = 0; i<arr.length-2; i++)
for(int j = i+1; j<arr.length-1; j++)
for(int k = j+1; k<arr.length; k++)
list.add(new int[]{arr[i],arr[j],arr[k]});
}
private static void listToString(List<int[]> list){
for(int i = 0; i<list.size(); i++){ //iterate through list
for(int j : list.get(i)){ //iterate through array
System.out.printf("%d ",j);
}
System.out.print("\n");
}
}
}
Run Code Online (Sandbox Code Playgroud)
Ale*_*you 48
这是生成所有k子集或k组合的充分研究的问题,其可以在没有递归的情况下容易地完成.
这个想法是具有尺寸的阵列k的保存序列索引从输入数组元素(它们是从数字0到n - 1)以递增的顺序.(然后可以通过从初始数组中通过这些索引获取项来创建子集.)因此我们需要生成所有这样的索引序列.
第一个索引序列将在[0, 1, 2, ... , k - 1]第二步切换到[0, 1, 2,..., k],然后转到[0, 1, 2, ... k + 1]依此类推.最后一个可能的顺序是[n - k, n - k + 1, ..., n - 1].
在每个步骤中,算法查找最接近最终项目的可递增的项目,递增它并将项目填充到该项目.
为了说明,考虑n = 7和k = 3.第一个索引序列是[0, 1, 2],[0, 1, 3]等等......在某些时候我们有[0, 5, 6]:
[0, 5, 6] <-- scan from the end: "6" cannot be incremented, "5" also, but "0" can be
[1, ?, ?] <-- "0" -> "1"
[1, 2, 3] <-- fill up remaining elements
next iteration:
[1, 2, 3] <-- "3" can be incremented
[1, 2, 4] <-- "3" -> "4"
Run Code Online (Sandbox Code Playgroud)
因此,[0, 5, 6]接着是[1, 2, 3],然后去[1, 2, 4]等.
码:
int[] input = {10, 20, 30, 40, 50}; // input array
int k = 3; // sequence length
List<int[]> subsets = new ArrayList<>();
int[] s = new int[k]; // here we'll keep indices
// pointing to elements in input array
if (k <= input.length) {
// first index sequence: 0, 1, 2, ...
for (int i = 0; (s[i] = i) < k - 1; i++);
subsets.add(getSubset(input, s));
for(;;) {
int i;
// find position of item that can be incremented
for (i = k - 1; i >= 0 && s[i] == input.length - k + i; i--);
if (i < 0) {
break;
}
s[i]++; // increment this item
for (++i; i < k; i++) { // fill up remaining items
s[i] = s[i - 1] + 1;
}
subsets.add(getSubset(input, s));
}
}
// generate actual subset by index sequence
int[] getSubset(int[] input, int[] subset) {
int[] result = new int[subset.length];
for (int i = 0; i < subset.length; i++)
result[i] = input[subset[i]];
return result;
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确的问题,这个文章似乎指向你想要做什么。
引用这篇文章:
方法1(修复元素并重复出现)
我们创建一个临时数组'data []',它一个接一个地存储所有输出。这个想法是从data []中的第一个索引(索引= 0)开始,在该索引处一个接一个的固定元素,然后为其余索引递归。令输入数组为{1、2、3、4、5},r为3。我们首先将1固定在data []中的索引0处,然后递归其余索引,然后将2固定在索引0处并递归。最后,我们修复3并递归剩余的索引。当data []中的元素数等于r(组合的大小)时,我们将打印data []。
方法2(包括和排除每个元素)
与上述方法一样,我们创建一个临时数组data []。这里的想法类似于子集和问题。我们一个接一个地考虑输入数组的每个元素,然后重复两种情况:
- 元素包含在当前组合中(我们将元素放入data []中,并在data []中增加下一个可用索引)
- 该元素被排除在当前组合之外(我们不放置该元素并且不更改索引)
当data []中的元素数等于r(组合的大小)时,我们将其打印出来。
| 归档时间: |
|
| 查看次数: |
57877 次 |
| 最近记录: |