Java 置换中的独立环

Java 置换中的独立环,java,c++,permutation,Java,C++,Permutation,我在创建一个函数时遇到问题,该函数将置换作为输入,并打印出独立的循环(在循环表示法中)。 我将感谢任何帮助 输入: 1 2 3 4 5 6 5 3 2 6 4 1 输出: (1 5 4 6)(2 3)从第一个数字(数字)开始,按照映射操作,直到返回到第一个数字。这是你的第一个周期 然后从下一个尚未访问的号码开始,并重复此过程 不断重复,直到访问完所有号码 ↓ 从第一个号码开始 1 2 3 4 5 6 1 5 3 2 6

我在创建一个函数时遇到问题,该函数将置换作为输入,并打印出独立的循环(在循环表示法中)。 我将感谢任何帮助

输入:

1 2 3 4 5 6             
        5 3 2 6 4 1
输出:


(1 5 4 6)(2 3)

从第一个数字(数字)开始,按照映射操作,直到返回到第一个数字。这是你的第一个周期

然后从下一个尚未访问的号码开始,并重复此过程

不断重复,直到访问完所有号码

↓             从第一个号码开始
1 2 3 4 5 6     1
5 3 2 6 4 1
*       ↓     1映射到5:
1 2 3 4 5 6     1 → 5.
5 3 2 6 4 1
*     ↓ *     5张地图到4张:
1 2 3 4 5 6     1 → 5.→ 4.
5 3 2 6 4 1
*     * * ↓   4张地图到6张:
1 2 3 4 5 6     1 → 5.→ 4.→ 6.
5 3 2 6 4 1
****6映射到1:
1 2 3 4 5 6     1 → 5.→ 4.→ 6.→ 1.
5 3 2 6 4 1完成第一个循环
*↓   * * *   从第一个未访问的号码开始:
1 2 3 4 5 6     2
5 3 2 6 4 1
* * ↓ * * *   2到3的地图:
1 2 3 4 5 6     2 → 3.
5 3 2 6 4 1
****3映射到2:
1 2 3 4 5 6     2 → 3.→ 2.
5 3 2 6 4 1秒循环完成
访问的所有数字,结果:
1.→ 5.→ 4.→ 6和2→ 3.⇒  (1546)(23)
现在您只需要用您喜欢的语言编写代码

提示:您需要3个数组,一个用于第一组数字,一个用于第二组数字,以及一个用于跟踪访问过哪些数字的数组

您还需要一些东西来捕获结果,例如,如果您使用Java,则需要一个
StringBuilder


更新

这是一个支持负数和多位数的Java解决方案,具有完整的输入验证:

private static String findCycles(int[] a, int[] b) {
    if (a.length == 0)
        throw new IllegalArgumentException("The sets cannot be empty");
    if (a.length != b.length)
        throw new IllegalArgumentException("Sets must have same size: " + a.length + " != " + b.length);
    TreeMap<Integer, Integer> numIdx = IntStream.range(0, a.length).boxed()
            .collect(Collectors.toMap(i -> a[i], Function.identity(),
                                      (i1, i2) -> { throw new IllegalArgumentException("Duplicate numbers not allowed: " + a[i1]); },
                                      TreeMap::new));
    if (! IntStream.of(b).boxed().collect(Collectors.toSet()).equals(numIdx.keySet()))
        throw new IllegalArgumentException("Sets must consist of the same numbers");
    String separator = (numIdx.firstKey() < 0 || numIdx.lastKey() > 9 ? " " : "");
    BitSet used = new BitSet(a.length);
    StringBuilder result = new StringBuilder();
    for (int idx; (idx = used.nextClearBit(0)) < a.length; ) {
        StringJoiner cycle = new StringJoiner(separator, "(", ")");
        do {
            used.set(idx);
            cycle.add(String.valueOf(a[idx]));
            idx = numIdx.get(b[idx]);
        } while (! used.get(idx));
        result.append(cycle.toString());
    }
    return result.toString();
}
输出

(1546)(23)
(146837)(2)(5)
(14625837)
(1)(24)(3)
(-5 0 5)(10)(15 20)
 > p>我将向您展示(许多)其中一个可能的解决方案和一个完整的C++实例。
我们只是沿着这两个排列的路径走。我们需要注意独立的循环,防止双循环,并需要避免无限循环通过循环

秘诀在于选择正确的容器类型。我用2。对于一个cyle,我使用了一个
std::unordered\u集
。这只能包含唯一的元素。这样,就可以避免无限循环。例如:0,1,3,0,1,3,0,1,3。不可能,因为每个数字在容器中只能有一次。这将一次又一次地阻止排列。一旦我们看到一个已经在循环中的数字,我们就会停止

所有找到的循环将存储在第二个容器类型中:A
std::set
std::set
也只能包含唯一的值,并且这些值是按顺序排列的

因为我们将复杂数据存储在
std::set
中,所以我们为它创建了一个自定义比较器。我们需要注意
std::set
不会包含2个双条目

在我们的例子中,double也是0,1,3和1,3,0。在我们的自定义比较器中,我们将首先将这两个集合复制到std::vector中,并对std::vector进行排序。这将使1,3,0变为0,1,3。这样我们就可以很容易地检测到替身

在下面的示例代码中,我总是只存储循环中第一次排列的值。第二个用作辅助对象,用于查找下一个要计算的值的索引

请参阅完整的工作示例:

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
#include <iterator>
#include <set>

// Make reading easier and define some alies names
using MyType = int;
using Cycle = std::unordered_set<MyType>;
using Permutation = std::vector<MyType>;
using Permutations = std::vector<Permutation>;

// We do not want to have double results. 
// A double cyle is also a Cycle with elements in different order
// So define custom comparator functor for our resulting set
struct Comparator {
    bool operator () (const Cycle& lhs, const Cycle& rhs) const {
        // Convert the unordered_sets to vectors
        std::vector<MyType> v1(lhs.begin(), lhs.end());
        std::vector<MyType> v2(rhs.begin(), rhs.end());
        // Sort them 
        std::sort(v1.begin(), v1.end());
        std::sort(v2.begin(), v2.end());
        // Compare them
        return v1 < v2;
    }
};
// Resulting cycles
using Cycles = std::set<Cycle, Comparator>;

int main() {

    // The source data
    Permutations perms2 = {
        {1,2,3,4,5,6},
        {5,3,2,6,4,1} };

    // Lamda to find the index of a given number in the first permutation
    auto findPos = [&perms2](const MyType& m) {return std::distance(perms2[0].begin(), std::find(perms2[0].begin(), perms2[0].end(), m)); };

    // Here we will store our resulting set of cycles
    Cycles resultingCycles{};

    // Go through all single elements of the first permutation
    for (size_t currentColumn = 0U; currentColumn < perms2[0].size(); ++currentColumn) {

        // This is a temporary for a cycle that we found in this loop
        Cycle trialCycle{};

        // First value to start with
        size_t startColumn = currentColumn;

        // Follow the complete path through the 2 permutations
        for (bool insertResult{ true }; insertResult; ) {

            // Insert found element from the first permutation in the current cycle
            const auto& [newElement, insertOk] = trialCycle.insert(perms2[0][startColumn]);

            // Find the index of the element under the first value (from the 2nd permutation)
            startColumn = findPos(perms2[1][startColumn]);

            // Check if we should continue (Could we inster a further element in our current cycle)
            insertResult = insertOk;
        }

        // We will only consider cycles with a length > 1
        if (trialCycle.size() > 1) {
            // Store the current temporary cycle as an additional result.
            resultingCycles.insert(trialCycle);
        }
    }

    // Show result. Simple output
    std::cout << "\n\nFound Cycles:\n\n";
    // Go through all found cycles
    for (const Cycle& c : resultingCycles) {
        // Print an opening brace
        std::cout << "(";
        // Handle the comma delimiter
        std::string delimiter{};

        // Print all integer values of the cycle
        for (const MyType& m : c) {
            std::cout << delimiter << m;
            delimiter = ",";
        }
        std::cout << ")";
    }
    std::cout << "\n\n";

    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
//使阅读更容易,并定义一些alies名称
使用MyType=int;
使用Cycle=std::无序_集;
使用置换=std::vector;
使用置换=std::vector;
//我们不希望出现双重结果。
//双循环也是元素顺序不同的循环
//因此,为我们的结果集定义自定义比较器函子
结构比较器{
布尔运算符()(常数循环和左、常数循环和右)常数{
//将无序的_集转换为向量
向量v1(lhs.begin(),lhs.end());
向量v2(rhs.begin(),rhs.end());
//分类
排序(v1.begin(),v1.end());
排序(v2.begin(),v2.end());
//比较它们
返回v11){
//将当前临时循环存储为附加结果。
结果周期。插入(三周期);
}
}
//显示结果。简单输出

大家好,非常感谢你们的解决方案,但我必须让它更简单。我应该使用2d dynamic
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>
#include <iterator>
#include <set>

// Make reading easier and define some alies names
using MyType = int;
using Cycle = std::unordered_set<MyType>;
using Permutation = std::vector<MyType>;
using Permutations = std::vector<Permutation>;

// We do not want to have double results. 
// A double cyle is also a Cycle with elements in different order
// So define custom comparator functor for our resulting set
struct Comparator {
    bool operator () (const Cycle& lhs, const Cycle& rhs) const {
        // Convert the unordered_sets to vectors
        std::vector<MyType> v1(lhs.begin(), lhs.end());
        std::vector<MyType> v2(rhs.begin(), rhs.end());
        // Sort them 
        std::sort(v1.begin(), v1.end());
        std::sort(v2.begin(), v2.end());
        // Compare them
        return v1 < v2;
    }
};
// Resulting cycles
using Cycles = std::set<Cycle, Comparator>;

int main() {

    // The source data
    Permutations perms2 = {
        {1,2,3,4,5,6},
        {5,3,2,6,4,1} };

    // Lamda to find the index of a given number in the first permutation
    auto findPos = [&perms2](const MyType& m) {return std::distance(perms2[0].begin(), std::find(perms2[0].begin(), perms2[0].end(), m)); };

    // Here we will store our resulting set of cycles
    Cycles resultingCycles{};

    // Go through all single elements of the first permutation
    for (size_t currentColumn = 0U; currentColumn < perms2[0].size(); ++currentColumn) {

        // This is a temporary for a cycle that we found in this loop
        Cycle trialCycle{};

        // First value to start with
        size_t startColumn = currentColumn;

        // Follow the complete path through the 2 permutations
        for (bool insertResult{ true }; insertResult; ) {

            // Insert found element from the first permutation in the current cycle
            const auto& [newElement, insertOk] = trialCycle.insert(perms2[0][startColumn]);

            // Find the index of the element under the first value (from the 2nd permutation)
            startColumn = findPos(perms2[1][startColumn]);

            // Check if we should continue (Could we inster a further element in our current cycle)
            insertResult = insertOk;
        }

        // We will only consider cycles with a length > 1
        if (trialCycle.size() > 1) {
            // Store the current temporary cycle as an additional result.
            resultingCycles.insert(trialCycle);
        }
    }

    // Show result. Simple output
    std::cout << "\n\nFound Cycles:\n\n";
    // Go through all found cycles
    for (const Cycle& c : resultingCycles) {
        // Print an opening brace
        std::cout << "(";
        // Handle the comma delimiter
        std::string delimiter{};

        // Print all integer values of the cycle
        for (const MyType& m : c) {
            std::cout << delimiter << m;
            delimiter = ",";
        }
        std::cout << ")";
    }
    std::cout << "\n\n";

    return 0;
}