这是打印字符串字符排列的标准函数:
void permute(char *a, int i, int n)
{
int j;
if (i == n)
printf("%s\n", a);
else
{
for (j = i; j < n; j++) //check till end of string
{
swap((a+i), (a+j));
permute(a, i+1, n);
swap((a+i), (a+j)); //backtrack
}
}
}
void swap (char *x, char *y)
{
char temp;
temp = *x;
*x = *y;
*y = temp;
}
它工作正常,但有一个问题,它还打印一些重复的排列,exapmle:
如果字符串是“AAB”
输出是:
AAB
ABA
AAB
ABA
BAA
BAA
这也有3个重复的条目。
有没有办法防止这种情况发生?
-
由于
Alok Kr。
答案 0 :(得分:13)
记下您之前交换过的字符:
char was[256];
/*
for(j = 0; j <= 255; j++)
was[j] = 0;
*/
bzero(was, 256);
for (j = i; j <= n; j++)
{
if (!was[*(a+j)]) {
swap((a+i), (a+j));
permute(a, i+1, n);
swap((a+i), (a+j)); //backtrack
was[*(a+j)] = 1;
}
}
这是迄今为止参赛作品中速度最快的一个,“AAAABBBCCD”(100循环)的一些基准:
native C - real 0m0.547s
STL next_permutation - real 0m2.141s
答案 1 :(得分:4)
标准库可满足您的需求:
#include <algorithm>
#include <iostream>
#include <ostream>
#include <string>
using namespace std;
void print_all_permutations(const string& s)
{
string s1 = s;
sort(s1.begin(), s1.end());
do {
cout << s1 << endl;
} while (next_permutation(s1.begin(), s1.end()));
}
int main()
{
print_all_permutations("AAB");
}
结果:
$ ./a.out
AAB
ABA
BAA
答案 2 :(得分:4)
另一种方法可能是:
预先排列阵列。
这将确保所有副本现在都是连续的。
所以,我们只需要查看我们修复的前一个元素(并置换其他元素)
如果当前元素与之前的元素相同,请不要置换。
答案 3 :(得分:3)
我会这样做:首先,我生成“组”字符(即AABBBC
产生两组:(AA) and (BBB) and (C)
。
首先,我们将AA
的所有分布迭代到n
个字符上。对于找到的每个分布,我们将BBB
的所有分布迭代到n-2
个剩余字符(未被A
占用)。对于涉及A
和B
s的每个分布,我们将C
的所有分布迭代到剩余的自由字符位置。
答案 4 :(得分:3)
您可以使用std::set
来确保结果的唯一性。那就是它是C ++(因为你是这样标记的)。
否则 - 手动浏览结果列表并删除重复项。
您必须保存结果并对其进行后期处理,而不是像现在一样立即打印。
答案 5 :(得分:1)
如果您认为这是一个需要存储所有排列以供将来使用的问题,那将非常简单。
所以你将拥有一系列置换字符串。
现在想一个新问题,这也是一个需要从数组中删除重复项的标准问题。
我希望有所帮助。
答案 6 :(得分:0)
@Kumar,我想你想要的是以下内容:
#include <stdio.h>
#include <string.h>
/* print all unique permutations of some text. */
void permute(int offset, int* offsets, const char* text, int text_size)
{
int i;
if (offset < text_size) {
char c;
int j;
/* iterate over all possible digit offsets. */
for (i=0; i < text_size; i++) {
c=text[i];
/* ignore if an offset further left points to our
location or to the right, with an identical digit.
This avoids duplicates. */
for (j=0; j < offset; j++) {
if ((offsets[j] >= i) &&
(text[offsets[j]] == c)) {
break;
}
}
/* nothing found. */
if (j == offset) {
/* remember current offset. */
offsets[offset]=i;
/* permute remaining text. */
permute(offset+1, offsets, text, text_size);
}
}
} else {
/* print current permutation. */
for (i=0; i < text_size; i++) {
fputc(text[offsets[i]], stdout);
}
fputc('\n', stdout);
}
}
int main(int argc, char* argv[])
{
int i, offsets[1024];
/* print permutations of all arguments. */
for (i=1; i < argc; i++) {
permute(0, offsets, argv[i], strlen(argv[i]));
}
return 0;
}
此代码为C,根据要求,它非常快,可以满足您的需求。当然它包含一个可能的缓冲区溢出,因为偏移缓冲区有一个固定的大小,但这只是一个例子,对吗?
编辑:有没有人试过这个?有更简单或更快的解决方案吗?令人失望的是没有人进一步发表评论!
答案 7 :(得分:0)
void permute(string set, string prefix = ""){
if(set.length() == 1){
cout<<"\n"<<prefix<<set;
}
else{
for(int i=0; i<set.length(); i++){
string new_prefix = prefix;
new_prefix.append(&set[i], 1);
string new_set = set;
new_set.erase(i, 1);
permute(new_set, new_prefix);
}
}
}
简单地使用它作为permute(“word”);
答案 8 :(得分:0)
请勿在{{1}}的不同位置置换相同的字符。
在Python中:
string
答案 9 :(得分:-1)
算法步骤:
我认为,这是最好,最有效的解决方案。