Java 大小为n的列表的所有可能k个组合
我试图从一个N码列表中得到K码的所有可能组合 我有一个接受“人类”对象的列表,我正在尝试创建一个新的ArrayList,其中将填充列表对象。每个列表都是“人类”对象的不同组合 一个简单的数字示例是:从一个由1,2,3组成的列表中,我想得到一个如下所示的数组列表:Java 大小为n的列表的所有可能k个组合,java,arrays,list,combinations,Java,Arrays,List,Combinations,我试图从一个N码列表中得到K码的所有可能组合 我有一个接受“人类”对象的列表,我正在尝试创建一个新的ArrayList,其中将填充列表对象。每个列表都是“人类”对象的不同组合 一个简单的数字示例是:从一个由1,2,3组成的列表中,我想得到一个如下所示的数组列表:[[1,2],[1,3],[2,3] 我也不介意它看起来像这样:[[1]、[2]、[3]、[1,2]、[1,3]、[2,3] 这是我的密码: public void combination(List<Human> people
[[1,2],[1,3],[2,3]
我也不介意它看起来像这样:[[1]、[2]、[3]、[1,2]、[1,3]、[2,3]
这是我的密码:
public void combination(List<Human> people, int k, ArrayList<List> result) {
if (people.size() < k) {
return;
}
if (k == 1) {
for (Human hum : people) {
List<Human> combinations = new ArrayList<Human>();
combinations.add(hum);
result.add(combinations);
}
}
else if (people.size() == k) {
List<Human> combinations = new ArrayList<Human>();
for (Human hum : people) {
combinations.add(hum);
}
result.add(combinations);
}
else if (people.size() > k) {
for (int i = 0; i < people.size(); i++) {
List<Human> combinations = new ArrayList<Human>();
combinations.add(people.get(i));
result.add(combinations);
combination(people.subList(i + 1, people.size()), k - 1, result);
}
}
}
public void组合(列出人员、int k、ArrayList结果){
if(people.size()k){
for(inti=0;i
我使用本网站的最后一种方法作为参考:
目前,我在新的ArrayList中获得了正确数量的结果,但其中的每个列表只包含一个人
我高度怀疑问题在于最后的else if
,因为我很难理解递归
请随意提出任何问题或建议任何其他实现。问题在您的循环中,您仅在连续子列表上调用
组合
函数(例如,如果初始集为[1,2,3,4,5],则不在[1,3,5]的子列表上调用函数)
另外,请记住,您应该重写Human
类中的equals
函数
private void subsetsOf(List<Human> humans, int k, int index, Set<Human> tempSet, List<Set<Human>> finalSet) {
if (tempSet.size() == k) {
finalSet.add(new HashSet<>(tempSet));
return;
}
if (index == humans.size())
return;
Human human = humans.get(index);
tempSet.add(human);
subsetsOf(humans, k, index+1, tempSet, finalSet);
tempSet.remove(human);
subsetsOf(humans, k, index+1, tempSet, finalSet);
}
public List<Set<Human>> combination(List<Human> humans, int k) {
List<Set<Human>> result = new ArrayList<>();
subsetsOf(humans, k, 0, new HashSet<Human>(), result);
return result;
}
private void subsetsOf(列出人、int k、int index、Set tempSet、List finalSet){
if(tempSet.size()==k){
添加(新HashSet(tempSet));
返回;
}
if(index==humans.size())
返回;
Human=humans.get(索引);
tempSet.add(人类);
子组(人类、k、指数+1、临时集、最终集);
tempSet.remove(人类);
子组(人类、k、指数+1、临时集、最终集);
}
公共列表组合(列表人,int k){
列表结果=新建ArrayList();
子集合(人类、k、0、新HashSet()、结果);
返回结果;
}
这里有另一个实现,它既不会删除任何内容,也不会创建虚假的内容列表。它只会在需要时添加,只要它们本身是唯一的,就没有等于T
所需的
只是为了学习经验,就在我脑海中:
package com.stackexchange.so;
import java.util.ArrayList;
import java.util.List;
public class RecursiveCombinationCreator {
/**
* Creates combinations of elements of a specific combination size.
*
* @param <T> the type of the elements
* @param elts a list of elements, which should be unique
* @param combinationSize the size of the combinations
* @return a list of combinations
*/
public static <T> List<List<T>> createCombinations(List<T> elts, int combinationSize) {
var fullCombinations = new ArrayList<List<T>>();
createCombinations(elts, fullCombinations, new ArrayList<T>(), 0, combinationSize);
return fullCombinations;
}
/**
* Recursive function that grows the combination size, and adds full combinations when the combination size is met.
* To avoid duplicates, only elements that are higher in the list are added to the combination. The combination is
* complete when <code>missing == 0</code>.
*
* @param <T> the type of the elements
* @param elts the elements to create combinations from, all elements should be unique
* @param fullCombinations the final result array of the combinations, shared among all recursive calls
* @param combination the current combination that needs to get <code>missing<code> members
* @param index the index of the element one higher than the last element in the combination
* @param missing the amount of elements needed to complete the combination
*/
private static <T> void createCombinations(List<T> elts, List<List<T>> fullCombinations, List<T> combination,
int index, int missing) {
if (missing == 0) {
fullCombinations.add(combination);
return;
}
// we don't need to go over elts.size() - missing because then the combination cannot be completed, too few left
for (int i = index; i <= elts.size() - missing; i++) {
List<T> newCombination;
if (i == elts.size() - missing) {
// optimization: avoid dereferencing the final combination, reuse
newCombination = combination;
} else {
newCombination = new ArrayList<T>(combination);
}
newCombination.add(elts.get(i));
createCombinations(elts, fullCombinations, newCombination, i + 1, missing - 1);
}
}
// === TEST CODE ===
// we needed humans, OK
private static class Human {
private int id;
public Human(int id) {
this.id = id;
}
@Override
public String toString() {
return Integer.toString(id);
}
}
public static void main(String[] args) {
// generate input
var humans = new ArrayList<Human>();
for (int id = 0; id < 200; id++) {
var human = new Human(id);
humans.add(human);
}
// just that one call
var fullcombinations = createCombinations(humans, 199);
// show output
System.out.println(fullcombinations.size());
for (List<Human> combination : fullcombinations) {
System.out.println(combination);
}
}
}
还要注意,最大深度等于k
(或k+1
),这意味着您的堆栈不会受到太多递归调用的影响。除了else if之外的所有内容都是快速跳过上一个循环的代码。在最后一个for
循环中,为每个人创建了一个组合,并且只添加了一个人,因此每个组合中当然只有一个人。我想名单上的每个人都是独一无二的?@MaartenBodewes谢谢你的回答,这是我的想法,但是我不知道如何修改“结果”以得到我需要的也许你错过了我评论中的问题?列表中没有重复吗?@MaartenBodewes是的,对不起,列表中的每个人都是唯一的,是的,没有重复。在最后一个循环中,我用较小的“k”和较小的人员列表递归地称之为重复。我想使用有序集也是可能的,但这需要重新思考。非常优雅的解决方案,我想也应该是最优的。