【问题标题】:Why does next_permutation skip some permutations?为什么 next_permutation 会跳过一些排列?
【发布时间】:2015-07-07 01:43:54
【问题描述】:

为什么这个简单的函数不输出输入的 5 个字母字符串的所有排列?我认为应该有 120,它只输出 90。

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;

// Creates permutation lists for strings
vector<string> createdcombos2(string letters)
{ 
    vector<string> lettercombos;    

    cout << "Letters are: " << letters << endl; //input string

    do 
        lettercombos.push_back(letters);        
    while(next_permutation(letters.begin(), letters.end()));    

    cout <<"Letter combos: " << endl;  //print out permutations 
    for (auto i : lettercombos)
        cout << i << endl;
    cout << endl << lettercombos.size() << endl; //number of permutations

    return lettercombos;
}


int main() 
{
    string letters = "gnary"; 
    vector<string> lettercombos;

    lettercombos = createdcombos2(letters);
}

【问题讨论】:

    标签: c++ permutation


    【解决方案1】:

    要返回循环中的所有排列直到 next_permutation 返回 false,必须在循环开始之前对向量进行排序。 next_permutation 按升序返回排列。因此,如果您从一个未排序的向量开始,它将从一系列排列开始。

    std::sort(letters.begin(), letters.end());
    do 
        lettercombos.push_back(letters);        
    while(next_permutation(letters.begin(), letters.end()));  
    

    【讨论】:

      【解决方案2】:

      您需要对输入进行排序,next_permutation 将按字典顺序返回下一个排列。因为输入排列:"gnary" 在字典上比诸如 "angry" 之类的排列“更大”,所以永远不会达到那些“较小”的排列。

      您可以使用std::sort()对字符串进行排序

      【讨论】:

        【解决方案3】:

        正如之前的一些答案所述,如果您想使用 bool 的返回值 std::next_permutation 来停止迭代,您必须确保从“排序”排列开始。否则,您的周期将提前终止。

        但这并不是绝对必要的。

        通过std::next_permutation枚举的排列形成一个没有开始或结束的循环序列,这意味着你可以无限期地调用std::next_permutation,它会再次循环通过120个排列的相同序列,一次又一次。这意味着您可以从该循环中的任何排列开始。你只需要记住你的起始排列并观察这个排列再次出现的那一刻。在您到达原始排列的那一刻,迭代就结束了。在您的情况下,预计需要 120 次调用 std::next_permutation

        例如,以下代码打印"abcde" 集合的所有 5 个字母排列,即使它从一个完全任意的排列开始

        std::string start = "cadeb", current = start;
        do
          std::cout << current << std::endl;
        while (std::next_permutation(current.begin(), current.end()), current != start);
        

        可以注意到,虽然在循环的每次迭代中比较排列比使用 std::next_permutation 的返回值更昂贵(它来自算法的内部“免费”),所以如果你对对起始排列进行预排序的解决方案,那么它确实是一种更有效的方法。

        或者,如果您知道循环中的确切排列次数(在本例中为 120 个),您可以简单地调用 std::next_permutation 确切的次数(如@Potatoswatter 的回答中所建议的那样)。

        【讨论】:

          【解决方案4】:

          next_permutation 的返回值bool 类似于溢出条件或进位位。它是false,它按照字典顺序从最后一个排列返回到第一个排列。但它仍然会无条件地前进。

          如果你知道正好有 120 个排列,你可以忽略返回值,只是盲目循环:

          for ( int i = 0; i != 120; ++ i ) {
              lettercombos.push_back(letters);        
              next_permutation(letters.begin(), letters.end());
          }
          

          【讨论】:

          • 只有当所有 5 个字母都不同时才会是 120。 (只是一个值得注意的评论)
          • 谢谢@Potatoswatter。这个答案对我来说非常有趣:) 在知道这一点之前,我写了一些 [愚蠢的] 函数来将输入向量转换为枚举映射,然后我对键(从 0 到输入向量的大小)进行排列以获得排列价值!
          猜你喜欢
          • 1970-01-01
          • 2020-04-10
          • 2013-09-20
          • 2015-10-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-22
          • 1970-01-01
          相关资源
          最近更新 更多