字符串的排列:如何删除重复的排列?

时间:2011-08-02 19:57:41

标签: c++ c algorithm permutation

这是打印字符串字符排列的标准函数:

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。

10 个答案:

答案 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)

另一种方法可能是:

  1. 预先排列阵列。

  2. 这将确保所有副本现在都是连续的。

  3. 所以,我们只需要查看我们修复的前一个元素(并置换其他元素)

  4. 如果当前元素与之前的元素相同,请不要置换。

答案 3 :(得分:3)

我会这样做:首先,我生成“组”字符(即AABBBC产生两组:(AA) and (BBB) and (C)

首先,我们将AA的所有分布迭代到n个字符上。对于找到的每个分布,我们将BBB的所有分布迭代到n-2个剩余字符(未被A占用)。对于涉及AB 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)

算法步骤:

  1. 将给定的字符串存储到临时字符串中,例如&#34; temp&#34;
  2. 从临时字符串
  3. 中删除重复项
  4. 最后调用&#34; void permute(char * a,int i,int n)&#34;函数打印给定字符串的所有排列而不重复
  5. 我认为,这是最好,最有效的解决方案。