【问题标题】:Permutation between two vectors两个向量之间的排列
【发布时间】:2015-11-24 07:22:48
【问题描述】:

我正在研究一些算法技术并陷入了一个问题,我需要在两组之间进行排列。例如:

[1,2,3] 和 [5,6,7]

需要生成:

[5,2,3] 和 [1,6,7]

[5,6,3] 和 [1,2,7]

........

等等。

据此到目前为止我所做的是在你们之间的一个向量中进行排列。

传递一个向量 [1,2,3]。生成答案: 123 132 213 231 321 312

基于以下代码:

public void permutar(int[] num, int idx) {
    for (int i = idx; i < num.length; i++) {
        swap(num, i, idx);
        permutar(num, idx + 1);
        swap(num, i, idx);
    }
    if (idx == num.length - 1) {
        for (int i = 0; i < num.length; i++) {
            System.out.print(num[i]);
        }
        System.out.println("");
    }
}

public void swap(int[] num, int a, int b) {
    int aux = num[a];
    num[a] = num[b];
    num[b] = aux;
}

如何在这两个向量之间进行置换?

【问题讨论】:

  • 你可以把它当作一个向量来使用,要么把它们真正放入一个向量中,要么用一个 getter 根据数量选择向量 1 或向量 2,然后排列。
  • [1,2,3]e[5,6,7] 和 [1,2,3,5,6,7] 的排列有什么区别。你不是简单地做 6 个数字的排列吗?
  • @flaschenpost 两个想法,一个想法 :-)
  • 我不能像一个向量那样使用简单,因为我不想花费计算处理在 1、2、3 之间进行置换,我只能在两个向量之间置换。有了这个 [2,1,3] 和 [5,6,7] 不是一个有效的排列。
  • 如果@Marco13 是正确的,您可以使用按位表示。即 000 表示 [1,2,3] e [5,6,7] ; 101 表示 [5,2,7] e [1,6,3] 。您只需从 0n 即可生成所有这些

标签: java algorithm


【解决方案1】:

虽然您没有准确描述您要查找的内容,并尝试回答:您似乎只是在查找输入的所有 3 元素子集(1、2、3、 5,6,7)。每个子集是一个解的第一个向量,其余元素是另一个向量。

这是一个如何计算此值的示例,基于我不久前编写的 ChoiceIterable 实用程序类:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

public class CombinationsOfVectors
{
    public static void main(String[] args)
    {
        List<Integer> input = Arrays.asList(1,2,3,5,6,7);

        ChoiceIterable<Integer> c = new ChoiceIterable<Integer>(3, input);
        for (List<Integer> v0 : c)
        {
            Set<Integer> s = new LinkedHashSet<Integer>(input);
            s.removeAll(v0);
            List<Integer> v1 = new ArrayList<Integer>(s);

            System.out.println(v0+" and "+v1);
        }
    }
}


// From https://github.com/javagl/Combinatorics/blob/master/src/
// main/java/de/javagl/utils/math/combinatorics/ChoiceIterable.java
// See the GitHub repo for a commented version
class ChoiceIterable<T> implements Iterable<List<T>>
{
    private final List<T> input;
    private final int sampleSize;
    private final long numElements;
    public ChoiceIterable(int sampleSize, List<T> input)
    {
        this.sampleSize = sampleSize;
        this.input = input;
        long nf = factorial(input.size());
        long kf = factorial(sampleSize);
        long nmkf = factorial(input.size() - sampleSize);
        long divisor = kf * nmkf;
        long result = nf / divisor;
        numElements = result;    
    }
    private static long factorial(int n)
    {
        long f = 1;
        for (long i = 2; i <= n; i++)
        {
            f = f * i;
        }
        return f;
    }    
    @Override
    public Iterator<List<T>> iterator()
    {
        return new Iterator<List<T>>()
        {
            private int current = 0;
            private final int chosen[] = new int[sampleSize];
            {
                for (int i = 0; i < sampleSize; i++)
                {
                    chosen[i] = i;
                }
            }
            @Override
            public boolean hasNext()
            {
                return current < numElements;
            }

            @Override
            public List<T> next()
            {
                if (!hasNext())
                {
                    throw new NoSuchElementException("No more elements");
                }

                List<T> result = new ArrayList<T>(sampleSize);
                for (int i = 0; i < sampleSize; i++)
                {
                    result.add(input.get(chosen[i]));
                }
                current++;
                if (current < numElements)
                {
                    increase(sampleSize - 1, input.size() - 1);
                }
                return result;
            }

            private void increase(int n, int max)
            {
                if (chosen[n] < max)
                {
                    chosen[n]++;
                    for (int i = n + 1; i < sampleSize; i++)
                    {
                        chosen[i] = chosen[i - 1] + 1;
                    }
                }
                else
                {
                    increase(n - 1, max - 1);
                }
            }

            @Override
            public void remove()
            {
                throw new UnsupportedOperationException(
                    "May not remove elements from a choice");
            }
        };
    }
}

本例中的输出将是

[1, 2, 3] and [5, 6, 7]
[1, 2, 5] and [3, 6, 7]
[1, 2, 6] and [3, 5, 7]
[1, 2, 7] and [3, 5, 6]
[1, 3, 5] and [2, 6, 7]
[1, 3, 6] and [2, 5, 7]
[1, 3, 7] and [2, 5, 6]
[1, 5, 6] and [2, 3, 7]
[1, 5, 7] and [2, 3, 6]
[1, 6, 7] and [2, 3, 5]
[2, 3, 5] and [1, 6, 7]
[2, 3, 6] and [1, 5, 7]
[2, 3, 7] and [1, 5, 6]
[2, 5, 6] and [1, 3, 7]
[2, 5, 7] and [1, 3, 6]
[2, 6, 7] and [1, 3, 5]
[3, 5, 6] and [1, 2, 7]
[3, 5, 7] and [1, 2, 6]
[3, 6, 7] and [1, 2, 5]
[5, 6, 7] and [1, 2, 3]

如果这不是您一直在寻找的,您应该更清楚、更准确地描述预期的结果。

(例如是否

[1, 2, 3] and [5, 6, 7]

[5, 6, 7] and [1, 2, 3]

计算不同的结果取决于您,但您可以相应地过滤结果)

【讨论】:

    【解决方案2】:

    您的任务等于列出您的 6 元素集的所有 3 元素子集。由于 3-Element-set 中的顺序无关紧要,因此您应该定义一个顺序,例如“较小的数字在前”。

    那么算法就很明显了:list = [1 2 3 5 6 7]

    编辑:Set1 应该始终是其中包含数字 1 的集合,以避免对称相同的解决方案。

    对于从 2 到 5 的所有数字 i 对于从 i+1 到 5 的所有数字 j Set1 = {列表[1],列表[i],列表[j]} Set2 = "其他数字"

    这应该从您的 9 元素评论中给出正确的排序列表。

    显然,这些是嵌套循环。

    【讨论】:

    • 这会给我 sets1 [123] [235] [356] [567] 的答案,然后这会给我一个索引超出范围的错误。因为 i = 5 j 将等于 6 而 k 等于 7(超出范围)。
    • 我已修复的索引问题,避免了对称解决方案。但是,如果需要,您真的应该尝试查看嵌套循环。我现在得到 123, 125, 126, 127, 135, 136, 137, 156, 157, 167 ,所以 4+3+2+1 = 10 个解决方案
    【解决方案3】:

    如 cmets to OP 问题中所述,您必须生成组合。通常的用例是从集合中获取一些元素的子集。在这个问题中,您采用表示从第一个集合中获取的元素的子集,其余的将从第二个集合中获取。

    为了实现组合,我建议使用从 0 到 2^n 的 for 循环计数(其中 n 是一个数组中的元素数)。然后取这个数字并用二进制表示。现在二进制表示中的每个 0 或 1 表示应该从哪个集合中指定数字(第二个集合将完全相反)。

    我猜您将此作为家庭作业或心理练习,因此不包括代码:]

    【讨论】:

    • 我不能那样做,因为一个数组中3个值的组合数不是2^3,不止于此。
    • @NicolasBontempo:2^3 没那么大。因此,只需列出这 8 个案例并告诉我们缺少什么。你说 [1,2,3] 和 [1,3,2] 对你来说是相等的,所以真的应该只有这 8 种情况。
    • @flaschenpost 对不起,你是对的。仅比 2^3 多 1。 [123][567] [125][367] [126][537] [127][563] [135][267] [136][267] [137][256] [156][237] [157] ][236] [167][235]
    • @NicolasBontempo 你是对的,000 - 111 是错的,所以 Vaclav Blazej 是错的。您从定义操作的整个集合 [1 2 3 5 6 7] 中取 6 个中的 3 个。
    • @flaschenpost 你用相同的解决方案描述操作;)
    猜你喜欢
    • 2022-11-24
    • 2013-02-03
    • 2018-06-22
    • 1970-01-01
    • 1970-01-01
    • 2013-08-22
    • 1970-01-01
    • 2012-12-29
    • 1970-01-01
    相关资源
    最近更新 更多