我需要通过选择一些元素来生成字符串的所有排列。就像我的字符串是“ abc”一样,输出将是{a,b,c,ab,ba,ac,ca,bc,cb,abc,acb,bac,bca,cab,cba}。
我想到了一种基本算法,在该算法中,我生成所有可能的{abc,b,c,ab,ac,bc,abc}的“ abc”组合,然后置换所有这些。
还有什么有效的置换算法,通过它我可以生成大小可变的所有可能置换。
我为此编写的代码是:
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <map> using namespace std; int permuteCount = 1; int compare (const void * a, const void * b) { return ( *(char*)a - *(char*)b); } void permute(char *str, int start, int end) { // cout<<"before sort : "<<str; // cout<<"after sort : "<<str; do { cout<<permuteCount<<")"<<str<<endl; permuteCount++; }while( next_permutation(str+start,str+end) ); } void generateAllCombinations( char* str) { int n, k, i, j, c; n = strlen(str); map<string,int> combinationMap; for( k =1; k<=n; k++) { char tempStr[20]; int index =0; for (i=0; i<(1<<n); i++) { index =0; for (j=0,c=0; j<32; j++) if (i & (1<<j)) c++; if (c == k) { for (j=0;j<32; j++) if (i & (1<<j)) tempStr[ index++] = str[j]; tempStr[index] = '\0'; qsort (tempStr, index, sizeof(char), compare); if( combinationMap.find(tempStr) == combinationMap.end() ) { // cout<<"comb : "<<tempStr<<endl; //cout<<"unique comb : \n"; combinationMap[tempStr] = 1; permute(tempStr,0,k); } /* else { cout<<"duplicated comb : "<<tempStr<<endl; }*/ } } } } int main () { char str[20]; cin>>str; generateAllCombinations(str); cin>>str; }
我需要使用散列来避免相同的组合,因此请让我知道如何使该算法更好。
谢谢,GG
我不认为您可以编写比现在更快的程序。主要问题是输出大小:它的顺序为n!*2^n(子集数*一个子集的平均排列数),该顺序已经> 10^9包含10个不同字符的字符串。
n!*2^n
> 10^9
由于STL next_permutation为这样的小字符串增加了非常有限的复杂性,因此程序的时间复杂度已经接近O(output size)。
next_permutation
O(output size)
但是您可以使程序更简单。特别地,for( k =1; k<=n; k++)循环似乎是不必要的:您已经在变量c内部计算了子集的大小。所以,只要有int k = c代替if (c == k)。(您还需要考虑空集的情况下:i == 0)
for( k =1; k<=n; k++)
c
int k = c
if (c == k)
i == 0
编辑 实际上,n == 10(没有~ 10^9)只有9864100输出。尽管如此,我的观点仍然是不变的:您的程序已经为每个输出仅浪费了“ O(next_permutation)”时间,这非常少。
n == 10
~ 10^9