簡體   English   中英

字符串的排列:如何刪除重復的排列?

[英]Permutation of String letters: How to remove repeated permutations?

這是打印字符串字符排列的標准函數:

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。

記下您之前交換過的字符:

 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. 預先排列陣列。

  2. 這將確保所有重復現在都是連續的。

  3. 所以,我們只需要查看我們修復的前一個元素(並置換其他元素)

  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

我會這樣做:首先,我生成“組”字符(即AABBBC產生兩組: (AA) and (BBB) and (C)

首先,我們將AA所有分布迭代到n字符上。 對於找到的每個分布,我們將BBB所有分布迭代到剩余的n-2字符(未被A占用)。 對於涉及A s和B s的這些分布中的每A ,我們將C所有分布迭代到剩余的自由字符位置上。

您可以使用std::set來確保結果的唯一性。 那就是它是C ++(因為你這樣標記它)。

否則 - 手動瀏覽結果列表並刪除重復項。

您必須保存結果並對其進行后處理,而不是像現在那樣立即打印。

如果您認為這是一個需要存儲所有排列以供將來使用的問題,那將非常簡單。

所以你將擁有一系列置換字符串。

現在想一個新問題,這也是一個標准的問題,你需要從數組中刪除重復項。

我希望有所幫助。

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);
            }
    }
}

只需將其用作置換(“單詞”);

不要在string不同位置置換相同的字符。

在Python中:

def unique_permutation(a, l, r):
    if l == r:
        print ''.join(a)
        return
    for i in range(l, r+1):
        if i != l and a[i] == a[l]:
            continue
        a[i], a[l] = a[l], a[i]
        unique_permutation(a, l+1, r)
        a[i], a[l] = a[l], a[i]

@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,根據要求,它非常快,可以滿足您的需求。 當然它包含一個可能的緩沖區溢出,因為偏移緩沖區有一個固定的大小,但這只是一個例子,對吧?

編輯:有沒有人試過這個? 有更簡單或更快的解決方案嗎? 令人失望的是沒有人評論任何進一步的評論!

算法步驟:

  1. 將給定的字符串存儲到臨時字符串中,例如“temp”
  2. 從臨時字符串中刪除重復項
  3. 最后調用“void permute(char * a,int i,int n)”函數來打印給定字符串的所有排列而不重復

我認為,這是最好,最有效的解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM