我无法找到一个简单的语句来跳过此递归排列代码的重复项。我到处寻找,似乎只找到使用swap或java的例子。从我收集的内容来看,我认为我需要在for-loop之后加上一行。
谢谢!
#include "genlib.h"
#include "simpio.h"
#include <string>
#include <iostream>
void ListPermutations(string prefix, string rest);
int main() {
cout << "Enter some letters to list permutations: ";
string str = GetLine();
cout << endl << "The permutations are: " << endl;
ListPermutations("", str);
return 0;
}
void ListPermutations(string prefix, string rest)
{
if (rest == "")
{
cout << prefix << endl;
}
else
{
for (int i = 0; i < rest.length(); i++)
{
if (prefix != "" && !prefix[i]) continue; // <--- I tried adding this, but it doesn't work
cout << endl<< "prefix: " << prefix << " | rest: " << rest << endl;
string newPrefix = prefix + rest[i];
string newRest = rest.substr(0, i) + rest.substr(i+1);
ListPermutations(newPrefix, newRest);
}
}
}
答案 0 :(得分:8)
这应该有效: 你的算法是好的,我只添加了一个测试:如果一个位置已经使用了一个独特的字符。如果是,则不再进行排列,因为已经在该位置使用该字符的所有排列。
void ListPermutations(string prefix, string rest)
{
if (rest == "")
{
cout << prefix << endl;
}
else
{
for (int i = 0; i < rest.length(); i++)
{
//test if rest[i] is unique.
bool found = false;
for (int j = 0; j < i; j++)
{
if (rest[j] == rest[i])
found = true;
}
if(found)
continue;
string newPrefix = prefix + rest[i];
string newRest = rest.substr(0, i) + rest.substr(i+1);
ListPermutations(newPrefix, newRest);
}
}
}
你也可以在进行排列之前对字符串进行排序,结果将是相同的。
答案 1 :(得分:4)
在C ++中使用std::next_permutation
生成排列它会处理重复的条目,并做正确的事
答案 2 :(得分:1)
忽略std :: next_permutation的可用性,因为你对前一个答案的评论......
如果要生成所有唯一排列,则需要在某些时候按顺序排列它们。最糟糕的方法是将它们全部放在一个向量中,对它进行排序,然后在打印出来时抑制重复的相邻条目。但这比它需要的要慢得多。
您需要先对字符串进行排序,以便相互之后生成相同的排列。然后在你的for循环中,确保你在'rest'中跳过任何重复的字母。类似的东西:
char lastAdditionToPrefix = '\0';
for (int i = 0; i < rest.length(); i++)
{
if (rest[i] == lastAdditionToPrefix) continue;
lastAdditionToPrefix = rest[i];
cout << endl<< "prefix: " << prefix << " | rest: " << rest << endl;
...
我不相信这个改变会完全修复你的代码,但它比你现在更接近。编辑:这个,加上对main()中的输入进行排序,将会起作用< / p>
答案 3 :(得分:0)
经过测试并且工作正常。这个想法是针对每个堆栈级别,在位置i,记住角色是否已经在该位置。
using namespace std;
void doPermutation(vector<char> &input, int index) {
bool used[26] = {false};
if(index == input.size()) {
copy(input.begin(), input.end(), ostream_iterator<char>(cout, "") );
cout << endl;
} else {
int i, j;
for(i =index; i < input.size(); i++ ) {
if(used[ input[i]-'a'] == false) {
swap(input[i], input[index]);
doPermutation(input, index+1);
swap(input[i], input[index]);
used[input[i]-'a'] = true;
}
}
}
}
void permutation(vector<char>& input) {
doPermutation(input, 0);
}
int main()
{
cout << "Hello World" << endl;
const char* inp = "alla";
vector<char> input(inp, inp + 4 );
permutation(input);
return 0;
}
答案 4 :(得分:0)
有或没有重复的算法的不同之处在于交换它时,请确保之前未交换过要交换的字符。使用哈希映射来跟踪之前交换的内容。
请参阅下面的C#代码。
private void PermuteUniqueHelper(int[] nums, int index, List<IList<int>> res)
{
var used = new Dictionary<int, bool>();
if (index == nums.Length)
{
res.Add(new List<int>(nums));
return;
}
for (int i = index; i < nums.Length; i++)
{
if (!used.ContainsKey(nums[i]))
{
swap(nums[i], nums[index]);
this.PermuteUniqueHelper(nums, index + 1, res);
swap(nums[i], nums[index]);
used.Add(nums[i], true);
}
}
}