我想获得由上界数组定义的集合的笛卡尔积。例如
int[] ub = [1,2]
描述集合{0,1}和{0,1,2}。笛卡尔乘积为{(0,0),(0,1),(0,2),(1,0),(1,1),(1,2)}
由于缺乏替代方案,我编写了以下代码,这些代码非常麻烦,可能效率不高。
public static int[][] combineRecursive(int[] ub) {
ArrayList<int[]> container = new ArrayList<int[]>();
combineRecursive(new int[0], 0, ub, container);
return container.toArray(new int[container.size()][]);
}
private static void combineRecursive(int[] node, int i, int[] ub, ArrayList<int[]> leafs) {
if (i == ub.length) {
leafs.add(node);
return;
}
for (int val = 0; val <= ub[i]; val++) {
int[] newNode = new int[node.length + 1];
System.arraycopy(node, 0, newNode, 0, node.length);
newNode[node.length] = val;
combineRecursive(newNode, i + 1, ub, leafs);
}
}
我的问题是
答案 0 :(得分:0)
考虑到您的确切问题,我认为有一种更简单,更有效的方法来构建您的解决方案。
你想在一系列仅由上界数组描述的序列中找到项目的笛卡尔积 - 让我们用你的两个上界[1,2]的例子代表两个序列{0,1}, {0,1,2}。
为了使它更简单 - 让我们假设在上界中排序没有重要性 - 数组[1,2]和数组[2,1]应该给我们带来相同的结果。
在这种情况下,您可以简单地将上限数组中的最大数字(即2)加1作为数字基数。我们现在将生成一系列数字,并将其基数为3的表示写入数组。不用担心,您不必知道如何计算基数3或进行任何特殊的基数3计算。我们仍然是十进制的,在此过程中使用日常数字。只需按照以下步骤操作:
1)按升序排列上限数组。这样可以在以后比较简单。
2)计算基数 - 最高上限加1。
3)计算一个数字,它是我们正在创建的序列的上限。我们将使用此数字后来循环。它是从右到左计算的:基于位置的力量,乘以位置的值。
在[1,2]的情况下,数字将是5:3 ^ 0 * 2,加上3 ^ 1 * 1 ==&gt; 2 + 3 ==&gt; 5.
4)进入从0到5的循环(前面步骤中找到的数字),查看Integer.toString(i,base)。检查基本表示字符串是否按字典顺序低于上限。如果是这样,请将其添加为结果整数数组。
这是一个代码示例。
public static void main(String[] args) {
//step 1 - getting the array in sorted order, and adding a string representation.
int[] upperBounds = {1,2};
String upperBoundsStr = "12";
int length = upperBounds.length;
int base=0;
Double rangeLimit=0.0;
List<int[]> cartesianProduct = new ArrayList<int[]>();
//step 2 - Find the base.
for (int i=0;i<length;i++) {
if (upperBounds[i]>base) {
base=upperBounds[i];
}
}
base++;
//step 3 - Find the range limit
for (int i=0;i<length;i++) {
Double upperBoundsNum=new Double(upperBounds[length-i-1]*java.lang.Math.pow(base, i));
rangeLimit+=upperBoundsNum;
}
//step 4 - Run over the range, and filter the non-relevant numbers
for (int i=0;i<=rangeLimit.intValue();i++) {
//Create a String representation of the number in the base. Add leading zeros.
String number = Integer.toString(i, base);
if (number.length()<upperBoundsStr.length()) {
String leadingZero = "";
for (int j=0;j<upperBoundsStr.length()-number.length();j++) {
leadingZero+="0";
}
number=leadingZero+number;
}
//Compare the base representation to the upper bounds string, lexicographically.
if (number.compareTo(upperBoundsStr)<=0) {
char[] numberToAddChr= number.toCharArray();
int[] numberToAdd = new int[numberToAddChr.length];
for (int j=0;j<numberToAddChr.length;j++){
numberToAdd[j] = (int) numberToAddChr[j];
}
cartesianProduct.add(numberToAdd);
}
}
}