大小为N和N的所有排列不一定等于数组

时间:2017-05-18 16:41:30

标签: c++ algorithm

我有一个值为{"Soa", "8", "m", "4", "8"}

的字符串向量

我想从大小为n的数组中打印所有排列而不重复(但在上面的向量中允许重复,如“8”),以指定大小k。我已经搜索过这方面的解决方案,但在这种情况下无法找到。

目前的代码是:

#include <algorithm>
#include <string>
#include <iostream>
#include <vector>

int main()
{
    std::vector<std::string> arr = { "Soa", "4", "m", "8", "8" };
    std::sort(arr.begin(), arr.end());


        do {
            for(auto& i: arr)
                std::cout << i;

            std::cout << '\n';
        } while(std::next_permutation(arr.begin(), arr.end()));
}

此代码仅打印矢量大小的所有排列(n=k),因此它打印出我需要的内容,但n=5。我想要的是指定n,例如n=2生成那些排列(打印它们的顺序无关紧要):

48
4Soa
4m
84
88
8Soa
8m
Soa4
Soa8
Soam
m4
m8
mSoa

编辑:由Nathan联系起来的解决方案不起作用,它将84与48相同。仍在寻找解决方案。

1 个答案:

答案 0 :(得分:1)

这个简单的函数在执行时间上并不是最佳的,但它的速度相当快,并且在程序员时间内绝对有效。它通过循环排列来构造部分排列,但是跳过不改变k元素前缀的排列。矢量必须在开头排序;否则事情就会破裂。

> 2017-05-15    1 
> 2017-05-12    3 
> 2017-05-10    4

该函数取决于template<typename BidiIt> bool next_partial_permutation(BidiIt first, BidiIt middle, BidiIt last) { std::reverse(middle, last); return std::next_permutation(first, last); } 按字典顺序递增顺序生成排列的事实。因此,它可以直接从具有给定k前缀的第一个置换到具有该前缀的最后一个置换,只需通过从位置k开始反转向量。

(具有给定k前缀的第一个排列具有从位置k开始排序的元素;最后一个具有以相反顺序排序的元素;因此反转这些元素意味着下一次调用next_permutation将产生下一个前缀。)

该功能是从this answer复制粘贴的,但我不认为这些问题足够相似,可以作为副本。

以下是如何使用它的示例。应该为程序提供值next_permutation作为其第一个命令行参数,然后是向量的k元素。 (它在启动之前对向量进行排序,因此您不需要确保对命令行参数进行排序。)

n

示例输出(live on coliru

int main(int argc, char** argv) {
    size_t k = std::atoi(argv[1]);
    std::vector<std::string> words(argv + 2, argv + argc);
    std::sort(words.begin(), words.end());
    do {
        for (size_t i = 0; i < k; ++i) std::cout << words[i];
        std::cout << '\n';
    } while (next_partial_permutation(words.begin(), words.begin() + k, words.end()));
    return 0;
}