递归地创建组合列表
Create a list of combinations recursively
我正在尝试使用递归实现组合方法。我已经使用 for 循环完成了它,但想通过递归来处理它。
该方法获取两个输入并创建所有可能的组合。它应该将组合存储在我称之为“组合”的实例变量中。我尝试了不同的代码,但它们无法正常工作。我认为递归回溯是解决这个问题的最佳方法。
例如,object.pe1.combination(4,3) 会创建如下内容:
image of combination list
// Instance variable needed for this problem
ArrayList<Integer[]> combination;
private int size;
// To calculate all the possible combinations
private int factorial(int x){
if (x == 0) {
return 1;
}
else {
return x * factorial(x - 1);
}
}
void combination(int n, int r) {
// formula for calculating the combination of r items selected among n: n! / (r! * (n - r)!)
int noc = factorial (n) / (factorial (r) * factorial (n - r)); // number of combinations
this.combination = new ArrayList<Integer[]>(noc); // 2D array. Each slot stores a combination
if (noc == 0) {
}
else {
this.combination = new ArrayList<Integer[]>(noc);
int[] arr = new int[n];
int[] temparr = new int[r];
arr = createCombination(temparr, 0, r);
}
}
private int[] createCombination(int[] temparr, int index, int r) {
// this is where I am stuck
temparr[0] = index;
if (temparr[r] == 0) {
temparr = new int[r - 1];
temparr = createCombination(temparr, index + 1, r - 1);
}
else {
return temparr;
}
}
任何算法的递归实现都由两部分组成:
- base case - 终止递归调用分支的条件,代表预先知道结果的边缘情况;
- 递归案例 - 逻辑驻留和递归调用的部分。
对于此任务,基本情况 将是组合大小等于目标大小(在您的代码中表示为 r
,在代码中下面我给它起了个名字targetSize
).
递归逻辑的解释:
- 每个方法调用都跟踪自己的
combination
;
- 除非达到
targetSize
,否则每个组合都用作 blue-print for other combinations
;
- 数据源中的每个项目都可以使用
only once
,因此当它被添加到组合时,必须从源中删除它。
您用来存储组合的类型 ArrayList<Integer[]>
不是一个好的选择。数组和泛型不能很好地结合在一起。 List<List<Integer>>
更适合此目的。
另外在我的代码中 List
被用作数据源而不是数组,这不是一个复杂的转换并且可以很容易地实现。
注意代码中的注释
private List<List<Integer>> createCombination(List<Integer> source, List<Integer> comb, int targetSize) {
if (comb.size() == targetSize) { // base condition of the recursion
List<List<Integer>> result = new ArrayList<>();
result.add(comb);
return result;
}
List<List<Integer>> result = new ArrayList<>();
Iterator<Integer> iterator = source.iterator();
while (iterator.hasNext()) {
// taking an element from a source
Integer item = iterator.next();
iterator.remove(); // in order not to get repeated the element has to be removed
// creating a new combination using existing as a base
List<Integer> newComb = new ArrayList<>(comb);
newComb.add(item); // adding the element that was removed from the source
result.addAll(createCombination(new ArrayList<>(source), newComb, targetSize)); // adding all the combinations generated
}
return result;
}
对于输入
createCombination(new ArrayList<>(List.of(1, 2, 3)), new ArrayList<>(), 2));
它将产生输出
[[1, 2], [1, 3], [2, 3]]
我正在尝试使用递归实现组合方法。我已经使用 for 循环完成了它,但想通过递归来处理它。
该方法获取两个输入并创建所有可能的组合。它应该将组合存储在我称之为“组合”的实例变量中。我尝试了不同的代码,但它们无法正常工作。我认为递归回溯是解决这个问题的最佳方法。
例如,object.pe1.combination(4,3) 会创建如下内容: image of combination list
// Instance variable needed for this problem
ArrayList<Integer[]> combination;
private int size;
// To calculate all the possible combinations
private int factorial(int x){
if (x == 0) {
return 1;
}
else {
return x * factorial(x - 1);
}
}
void combination(int n, int r) {
// formula for calculating the combination of r items selected among n: n! / (r! * (n - r)!)
int noc = factorial (n) / (factorial (r) * factorial (n - r)); // number of combinations
this.combination = new ArrayList<Integer[]>(noc); // 2D array. Each slot stores a combination
if (noc == 0) {
}
else {
this.combination = new ArrayList<Integer[]>(noc);
int[] arr = new int[n];
int[] temparr = new int[r];
arr = createCombination(temparr, 0, r);
}
}
private int[] createCombination(int[] temparr, int index, int r) {
// this is where I am stuck
temparr[0] = index;
if (temparr[r] == 0) {
temparr = new int[r - 1];
temparr = createCombination(temparr, index + 1, r - 1);
}
else {
return temparr;
}
}
任何算法的递归实现都由两部分组成:
- base case - 终止递归调用分支的条件,代表预先知道结果的边缘情况;
- 递归案例 - 逻辑驻留和递归调用的部分。
对于此任务,基本情况 将是组合大小等于目标大小(在您的代码中表示为 r
,在代码中下面我给它起了个名字targetSize
).
递归逻辑的解释:
- 每个方法调用都跟踪自己的
combination
; - 除非达到
targetSize
,否则每个组合都用作blue-print for other combinations
; - 数据源中的每个项目都可以使用
only once
,因此当它被添加到组合时,必须从源中删除它。
您用来存储组合的类型 ArrayList<Integer[]>
不是一个好的选择。数组和泛型不能很好地结合在一起。 List<List<Integer>>
更适合此目的。
另外在我的代码中 List
被用作数据源而不是数组,这不是一个复杂的转换并且可以很容易地实现。
注意代码中的注释
private List<List<Integer>> createCombination(List<Integer> source, List<Integer> comb, int targetSize) {
if (comb.size() == targetSize) { // base condition of the recursion
List<List<Integer>> result = new ArrayList<>();
result.add(comb);
return result;
}
List<List<Integer>> result = new ArrayList<>();
Iterator<Integer> iterator = source.iterator();
while (iterator.hasNext()) {
// taking an element from a source
Integer item = iterator.next();
iterator.remove(); // in order not to get repeated the element has to be removed
// creating a new combination using existing as a base
List<Integer> newComb = new ArrayList<>(comb);
newComb.add(item); // adding the element that was removed from the source
result.addAll(createCombination(new ArrayList<>(source), newComb, targetSize)); // adding all the combinations generated
}
return result;
}
对于输入
createCombination(new ArrayList<>(List.of(1, 2, 3)), new ArrayList<>(), 2));
它将产生输出
[[1, 2], [1, 3], [2, 3]]