为啥 std::next_permutation 会跳过一些排列?

Posted

技术标签:

【中文标题】为啥 std::next_permutation 会跳过一些排列?【英文标题】:Why is std::next_permutation skipping over some permutations?为什么 std::next_permutation 会跳过一些排列? 【发布时间】:2021-04-24 21:49:52 【问题描述】:

“opt”(或这 3 个字母的任意组合)的预期输出应该是“opt”、“top”和“pot”(以任意顺序),但该程序仅查找和匹配“top”和“锅”。 next_permutation 似乎永远不会超过“选择”,我不确定问题是什么。尝试查找“apt”的所有排列时也会出现同样的问题。

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

//int loadDictionary(istream& dictfile, vector<string>& dict);

int permute(string word, vector<string>& dict, vector<string>& results) 
std::sort(word.begin(), word.end());
while (next_permutation(word.begin(), word.end()))
    cout << "Permutation: " << word << endl;
    if (binary_search(dict.begin(), dict.end(), word)) 
        cout << "Match found: " << word << endl;
        results.push_back(word);
    


    int matches = results.size();
    return matches;


int main() 
std::vector<string> dictionary;
std::vector<string> results;
std::string word;
ifstream fileName("words.txt");
cout << loadDictionary(fileName, dictionary);
cout << "\nEnter a string for a anagram: ";
    cin >> word;
    permute(word, dictionary, results);
cout << "\nMain complete\n";


【问题讨论】:

第 12 行的 while (next_permutation(word.begin(), word.end())) 将在循环第一次进入之前对单词 进行置换,这会导致第一个置换丢失。解决此问题的一种方法是将您的 while 循环更改为 do-while 循环,这将通过在实际排列之前处理初始单词来解决您的问题。 见en.cppreference.com/w/cpp/algorithm/next_permutation的例子 @Telescope 谢谢,将其更改为 do while 循环修复了它。从来没有想过使用它,因为我认为当 while 循环通常完成这项工作时它是多余的。我知道这超出了问题的范围,但是您知道为什么二进制搜索与某些单词不匹配吗?它适用于线性搜索,但显然效率要低得多。 二分搜索需要对被搜索的容器进行排序。我猜不是。 @JohnFilleau 文本文件包含 25,000 个按字母顺序排列的单词,所以我认为情况并非如此。我已经使用 cout 仔细检查了。 【参考方案1】:

std::next_permutation 进行排列,所以经常使用do while

int permute(std::string word, std::vector<std::string>& dict, std::vector<std::string>& results) 
    std::sort(word.begin(), word.end());
    do 
        std::cout << "Permutation: " << word << std::endl;
        if (std::binary_search(dict.begin(), dict.end(), word)) 
            std::cout << "Match found: " << std::word << std::endl;
            results.push_back(word);
     while (next_permutation(word.begin(), word.end()));
    int matches = results.size();
    return matches;

要检查字典,检查所有排列似乎很庞大。

您可以将您的字典转换为“字谜”字典。

std::map<std::string, std::vector<string>> make_anagram_dict(const std::vector<string>& words)

    std::map<std::string, std::vector<string>> res;

    for (const auto& word : words) 
        auto anagram = word;
        std::sort(anagram.begin(), anagram.end());
        res[anagram].push_back(word);
    
    return res;

那么你的主要是

int main() 
    std::vector<string> words;
    ifstream fileName("words.txt");
    loadDictionary(fileName, words);
    auto dict = make_anagram_dict(words);
    do 
       std::cout << "\nEnter a string for a anagram: ";
       std::string anagram;
       std::cin >> anagram;
       std::sort(anagram.begin(), anagram.end());
       auto it = dict.find(anagram);
       if (it != dict.end()) 
           for (const auto& word : it->second) 
               std::cout << "Match found: " << word << std::endl;
           
       
     while (std::cin); // or other conditions to break the loop
    std::cout << "\nMain complete\n";

【讨论】:

以上是关于为啥 std::next_permutation 会跳过一些排列?的主要内容,如果未能解决你的问题,请参考以下文章

将 std::next_permutation 与 2D 数组一起使用

C++ STL应用与实现62: 如何使用std::next_permutation

C++ STL应用与实现62: 如何使用std::next_permutation

C++ 全排列函数 nyoj 366

LeetCodePermutation全排列

全排列permutation