【问题标题】:Print all permutations of selected length characters with repetition and do not start over after closing the program in CPP [closed]重复打印所选长度字符的所有排列,并且在 CPP 中关闭程序后不要重新开始 [关闭]
【发布时间】:2021-03-23 08:17:35
【问题描述】:
#include <iostream>
#include <string>

using namespace std;

void enumerate(const string& s, int n, string t = "")
{
    if (n == 0)
        cout << t << endl;
    else
    {
        for (char c : s)
            enumerate(s, n - 1, t + c);
    }
}

int main()
{
    enumerate("abc", 5);
}

嗨,伙计们,我想对选定长度的字符进行所有可能的排列,但可能电源没电了,或者我突然关闭了程序,或者我必须重新启动计算机,所以我应该再次打开程序并重新开始这样我们的时间和精力就会浪费掉。 我也不知道这种类型的 for 循环是如何工作的(for (char c : s))所以我怎样才能保存进度, 例如,如果循环工作了 100 次,则将数字 100 保存在文本文件或其他所有内容中,然后,如果我出于某种原因关闭程序并再次打开,则从文本文件中读取数字 100 并且不要' t 重新开始并继续循环。

【问题讨论】:

  • 检查 n &lt; s.length() 在您的 enumerate() 函数中。
  • 您似乎想要笛卡尔积,而不是排列。
  • 问题是什么?

标签: c++ for-loop permutation cartesian-product


【解决方案1】:

处理字符串排列

C++ 有一个方便的标准库算法std::next_permutation,您可以使用它来为您处理字符串排列。

一个解决方案

下面是一种蛮力方法,其中对较大的“父”字符串的每个可能的排列进行迭代,并测试第一个 n 字符子字符串的唯一性。如果该子子字符串是唯一的,则将其打印并添加到“已使用”子排列集合中。

每次迭代后,您都可以保存当前的父排列状态。您可以稍后将其传递给print_permutation 函数,该函数将从该点恢复排列计算。有关详细信息,请参阅下面的实现。

#include <algorithm>
#include <functional>
#include <iostream>
#include <string>
#include <unordered_set>

typedef std::function<void(const std::string& masterPerm, const bool finished)> PermutationCallback;

std::string new_master_permutation(std::string&& str) {
  std::sort(str.begin(), str.end());
  return str;
}

void print_permutation_if_unused(
  const std::string& childPermutation,
  std::unordered_set<std::string>& childPermsTried
) {
  if (!childPermsTried.contains(childPermutation)) {
    childPermsTried.insert(childPermutation);
    std::cout << childPermutation << '\n';
  }
}

void print_permutations(
  std::string masterPermutation,
  const size_t numCharsInPerm,
  const PermutationCallback& callback
) {
  std::unordered_set<std::string> childPermsTried;
  // Actual constrained length of child permutation strings
  const size_t permutationLength = std::min(masterPermutation.size(), numCharsInPerm);

  do {
    print_permutation_if_unused(masterPermutation.substr(0, permutationLength), childPermsTried);
    callback(masterPermutation, false);
  } while (std::next_permutation(masterPermutation.begin(), masterPermutation.end()));

  callback(masterPermutation, true);
}

int main(void) {
  // Begin with a new permutation, starting with the sorted string "abbc"
  print_permutations(new_master_permutation("bacb"), 3,
    [](const std::string& masterPerm, const bool finished) {
      // Save the master permutation for reference
    }
  );

  // Begin at any midpoint permutation ("bacb"), and calculate the rest.
  print_permutations("bacb", 3, [](const std::string& masterPerm, const bool finished) {
    // Save the master permutation for reference
  });
  return EXIT_SUCCESS;
}

请注意,此实现远非最佳。随着每个字符添加到主排列字符串,执行时间会增加。较大的子排列长度会大大增加内存使用,因为每个唯一排列都存储在一个集合中。但是,它确实有效,并且至少应该提供一个良好的起点。

【讨论】:

  • 感谢您的完整回答和真实的解释,但只是有一个小问题,在第 18 行命令 .contains 是错误的我已经尝试过 MinGW c++ 11 和 VS 编译器,但它没有工作.
  • 对,对不起。 .contains 是 C++ 20 的一部分。将条件替换为 childPermsTried.emplace(childPermutation) == childPermsTried.end(),它将适用于 C++ 11。第 19 行中的 insert 调用也需要更改为 emplace,因为 insert 是 C++17 的一部分.
猜你喜欢
  • 2020-05-03
  • 2013-12-30
  • 1970-01-01
  • 2013-03-13
  • 2016-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多