【问题标题】:Perfoming Cartesian product on arrays执行数组的笛卡尔积
【发布时间】:2012-05-31 19:57:36
【问题描述】:

我有兴趣在 n 个数组上执行笛卡尔积。如果我提前知道数组的数量,我可以编写代码。例如,给定 2 个数组:

int[] a = new int[]{1,2,3};
int[] b = new int[]{1,2,3};

for(int i=0; i<=a.length; i++){
    for(int j=0; j<=b.length; j++){
        System.out.println(a[i]*b[j]);
    }
}

问题是在运行时,我不知道数组的数量。我可能有 2 个数组,或者我可能有 100 个数组。有没有办法我可以做到这一点?谢谢!

【问题讨论】:

标签: java algorithm math multiplication


【解决方案1】:

解决这个问题的一种方法是不断减少数组的数量,同时注意这一点

A0 × A1 × A2 = (A0 × A1) × A2

因此,您可以编写这样的函数,计算两个数组的笛卡尔积:

int[] cartesianProduct(int[] one, int[] two) {
    int[] result = new int[one.length * two.length];
    int index = 0;

    for (int v1: one) {
        for (int v2: two) {
            result[index] = v1 * v2;
            index++;
        }
    }

    return result;
}

现在,您可以使用此函数将数组对组合成一个包含整个笛卡尔积的数组。在伪代码中:

While there is more than one array left:
    Remove two arrays.
    Compute their Cartesian product.
    Add that array back into the list.
Output the last array.

而且,作为真正的 Java:

Queue<int[]> worklist;
/* fill the worklist with your arrays; error if there are no arrays. */

while (worklist.size() > 1) {
    int[] first = worklist.remove();
    int[] second = worklist.remove();
    worklist.add(cartesianProduct(first, second));
}

/* Obtain the result. */
int[] result = worklist.remove();

这种方法的问题在于它使用的内存与您生成的元素总数成正比。这可能是一个非常大的数字!如果您只想一次打印所有值而不存储它们,则有一种更有效的方法。这个想法是,您可以开始列出不同数组中所有可能的索引组合,然后将这些位置的值相乘。一种方法是维护一个“索引数组”,说明下一个要查看的索引是什么。您可以通过“增加”数组来从一个索引移动到下一个索引,就像增加一个数字一样。下面是一些代码:

int[] indexArray = new int[arrays.length];
mainLoop: while (true) {
    /* Compute this entry. */
    int result = 1;
    for (int i = 0; i < arrays.length; i++) {
        result *= arrays[i][indexArray[i]]
    }
    System.out.println(result);

    /* Increment the index array. */
    int index = 0;
    while (true) {
        /* See if we can bump this array index to the next value.  If so, great!
         * We're done.
         */
        indexArray[index]++;
        if (indexArray[index] < arrays[i].length) break;

        /* Otherwise, overflow has occurred.  If this is the very last array, we're
         * done.
         */
        indexArray[index] = 0;
        index ++;

        if (index == indexArray.length) break mainLoop;
    }
}

这仅使用 O(L) 内存,其中 L 是您拥有的数组的数量,但可能会产生指数级的许多值。

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    您可以使用递归而不是迭代 - 但请注意 - 可能会发生 StackOverflowException。

    【讨论】:

    • 我知道你在说什么解决方案,但如果你还不知道你的想法,我认为这个答案不会有太大帮助。
    • 我怀疑你会遇到 StackOverflowException,除非你有一堆大小为 1 的集合。即使大小为 2 的集合,你也使用指数内存并且只有线性堆栈空间,所以你会很多内存用完比堆栈快。
    猜你喜欢
    • 2011-11-11
    • 2017-03-05
    • 2011-12-18
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 2018-03-09
    • 2016-07-10
    相关资源
    最近更新 更多