我不会编写代码,但会列出一种可能的方法。我说可能是因为它将运行并将所有数据存储在内存中,并且在算法方面不是最好的。然而,这是一种不需要消除无效选项的方法。为了让事情更清楚,我将使用一个例子。
假设您有类别 A、B、C。其中 A、B 的 K=2 和 C 的 K=1。您还有输入项 A1、B1、B2、A2、C1、A3
1-检查项目并根据它们的类别划分它们。因此,您为每个类别准备一个数组/列表,其中包含属于它的所有项目。
所以现在你有数组:
类别 A = [A1,A2,A3] ,类别 B = [B1,B2] 和类别 C=[C1]
2-现在在准备好列表之后,准备好你可以拥有的各种法律组,以便从该列表中找到的 N 项中挑选 K 项。这是一个可能有助于有效地做到这一点的链接:How to iteratively generate k elements subset from a set of size n in java?
现在你有:
属于 A 类的第一组:[A1,A2]、[A1,A3]、[A2,A3](3 个元素)
属于 B 类的第二组:[B1,B2](1 个元素)
属于 C 类的第三组:[C1](1 个元素)
3-现在,如果您将每个这样的组视为一个项目,那么问题就会转变为有多少种不同的方式可以从每个组中准确地选择一个元素。这应该更容易递归编程,并且不需要消除选项。如果类别的数量是恒定的,它将在上面第二点的组集上嵌套循环。
编辑
该方法在消除验证不良组合的需要方面效果很好。但是,时间上还是会有问题。这是我用来演示的代码。它列出了 100 个项目。然后它会执行提到的步骤。请注意,我注释掉了打印组的代码。到那时,计算速度非常快。我添加了代码,打印出每个组可以做出多少合法选择。
package tester;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
/**
*
* @author
*/
public class Tester {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
//generate 100 random items belonging to categories
Random rand=new Random();
List<Item> items=new ArrayList<>();
int a=1,b=1,c=1,d=1,e=1;
for (int i=0;i<100;i++){
int randomNumber=rand.nextInt(5)+1;
CATEGORY_TYPE categoryType=null;
int num=0;
switch (randomNumber) {
case 1:
categoryType=CATEGORY_TYPE.A;
num=a++;
break;
case 2:
categoryType=CATEGORY_TYPE.B;
num=b++;
break;
case 3:
categoryType=CATEGORY_TYPE.C;
num=c++;
break;
case 4:
categoryType=CATEGORY_TYPE.D;
num=d++;
break;
case 5:
categoryType=CATEGORY_TYPE.E;
num=e++;
break;
}
String dummyData="Item "+categoryType.toString()+num;
Item item=new Item(dummyData,categoryType);
items.add(item);
}
//arrange the items in lists by category
List<Item> categoryAItemsList=new ArrayList<>();
List<Item> categoryBItemsList=new ArrayList<>();
List<Item> categoryCItemsList=new ArrayList<>();
List<Item> categoryDItemsList=new ArrayList<>();
List<Item> categoryEItemsList=new ArrayList<>();
for (Item item:items){
if (item.getCategoryType()==CATEGORY_TYPE.A)
categoryAItemsList.add(item);
else if (item.getCategoryType()==CATEGORY_TYPE.B)
categoryBItemsList.add(item);
else if (item.getCategoryType()==CATEGORY_TYPE.C)
categoryCItemsList.add(item);
else if (item.getCategoryType()==CATEGORY_TYPE.D)
categoryDItemsList.add(item);
else if (item.getCategoryType()==CATEGORY_TYPE.E)
categoryEItemsList.add(item);
}
//now we want to construct lists of possible groups of choosing from each category
List<Item[]> subsetStoringListA=new ArrayList<>();
List<Item[]> subsetStoringListB=new ArrayList<>();
List<Item[]> subsetStoringListC=new ArrayList<>();
List<Item[]> subsetStoringListD=new ArrayList<>();
List<Item[]> subsetStoringListE=new ArrayList<>();
processSubsets(categoryAItemsList.toArray(new Item[0]),2,subsetStoringListA);
processSubsets(categoryBItemsList.toArray(new Item[0]),2,subsetStoringListB);
processSubsets(categoryCItemsList.toArray(new Item[0]),2,subsetStoringListC);
processSubsets(categoryDItemsList.toArray(new Item[0]),2,subsetStoringListD);
processSubsets(categoryEItemsList.toArray(new Item[0]),1,subsetStoringListE);
System.out.println(" A groups number: "+subsetStoringListA.size());
System.out.println(" B groups number: "+subsetStoringListB.size());
System.out.println(" C groups number: "+subsetStoringListC.size());
System.out.println(" D groups number: "+subsetStoringListD.size());
System.out.println(" E groups number: "+subsetStoringListE.size());
//now we just print all possible combinations of picking a single group from each list.
//the group is an array with valid choices
// for (Item[] subsetA:subsetStoringListA){
// for (Item[] subsetB:subsetStoringListB){
// for (Item[] subsetC:subsetStoringListC){
// for (Item[] subsetD:subsetStoringListD){
// for (Item[] subsetE:subsetStoringListE){
// print(subsetA);
// print(subsetB);
// print(subsetC);
// print(subsetD);
// print(subsetE);
// System.out.println("\n");
// }
//
// }
// }
// }
// }
}
static void print(Item[] arr){
for (Item item:arr)
System.out.print(item.getDumyData()+" ");
}
static void processSubsets(Item[] set, int k,List<Item[]> subsetStoringList) {
Item[] subset = new Item[k];
processLargerSubsets(set, subset, 0, 0,subsetStoringList);
}
static void processLargerSubsets(Item[] set, Item[] subset, int subsetSize, int nextIndex,List<Item[]> subsetStoringList) {
if (subsetSize == subset.length) { //here we have a subset we need to store a copy from it
subsetStoringList.add(Arrays.copyOf(subset, subset.length));
} else {
for (int j = nextIndex; j < set.length; j++) {
subset[subsetSize] = set[j];
processLargerSubsets(set, subset, subsetSize + 1, j + 1,subsetStoringList);
}
}
}
public static enum CATEGORY_TYPE {A,B,C,D,E}
private static class Item{
private CATEGORY_TYPE categoryType;
private String dumyData;
public Item(String dumyData,CATEGORY_TYPE categoryType) {
this.dumyData = dumyData; //maybe bad name but i mean the object can have many other fields etc
this.categoryType = categoryType;
}
/**
* @return the categoryType
*/
public CATEGORY_TYPE getCategoryType() {
return categoryType;
}
/**
* @return the dumyData
*/
public String getDumyData() {
return dumyData;
}
}
}
在特定的运行中,它给出了以下内容:
A组数:210 B组数:153 C组数:210 D组数:210 E组数:19
这意味着,如果我们必须从每个元素中打印出单个元素的所有可能选择(这里的元素是一个包含某个类别的 k 个选择的数组),您将拥有:210*153*210*210*19 = 26,921,727,000现在列出/打印超过 260 亿个变体无论如何都需要时间,而且我不知道如何将其最小化。
尝试将项目总数设置为 20 并取消注释打印代码以查看一切正常。看看你是否真的需要列出可能的组合。请记住,这里的每个组合都是合法的,并且代码的所有部分都没有浪费的迭代。最后一点:我没有像当类别中没有项目可以完成 K 那样处理边缘情况。在这种情况下,您可以根据所需的行为轻松放入代码中。