题目:给定字符串S[0...N-1],设计算法,枚举S的全排列。
假设字符串为“1234”,首先考虑1,然后问题就变成了考虑“234”的全排列,所以问题规模缩小了1,然后再考虑2,依次类推。可以采用递归算法。
1-234
2-134
3-124
4-123
假设有重复字符,则重复字符的全排列就是每个字符分别与它后面非重复出现的字符交换。
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 //递归算法 7 void swap(char &c1, char &c2) 8 { 9 char temp = c1; 10 c1 = c2; 11 c2 = temp; 12 return; 13 } 14 //判断是否交换 15 bool IsSwap(string str,int from, int to) 16 { 17 //默认交换 18 bool cnt = true; 19 for(int i = from; i < to; ++i) 20 { 21 if(str[i] == str[to]) 22 { 23 cnt = false; 24 break; 25 } 26 } 27 return cnt; 28 } 29 //from和to 是下标 30 void Permutation(string str, int from, int to) 31 { 32 if(from == to) 33 { 34 for(int i = 0; i <= to; ++i) 35 { 36 cout << str[i]; 37 } 38 cout << endl; 39 return; 40 } 41 for(int i = from; i <= to; ++i) 42 { 43 if(!IsSwap(str,from, i)) 44 continue; 45 swap(str[i], str[from]); 46 Permutation(str, from + 1, to); 47 swap(str[i], str[from]); 48 } 49 return; 50 } 51 52 int main(int argc, const char *argv[]) 53 { 54 string str = "1223"; 55 int len = str.size(); 56 Permutation(str, 0, len-1); 57 return 0; 58 }
测试用例为“1234”和“1223”
结果为:
这里有个小技巧,可以减少有重复字符全排列的时间复杂度,通过空间换时间。
如果是单字符,可以使用mark[256]。
如果是整数,可以遍历整数得到最大值max和最小值min,使用mark[max-min+1]。
如果是浮点数或者其他结构数据,用Hash(事实上,如果发现整数间变化太大,也应该考虑使用Hash;并且,可以认为整数情况是最朴素的Hash)
将mark数组全部赋0,每次交换前将mark[i]赋1,然后每次要进行交换前进行判断即可。
代码只修改这一部分,其余部分一样:
40 int mark[256]; 41 for(int i = 0; i < 256; ++i) 42 { 43 mark[i] = 0; 44 } 45 for(int i = from; i <= to; ++i) 46 { 47 if(mark[str[i]] == 1) 48 continue; 49 /*if(!IsSwap(str,from, i)) 50 continue; 51 */ 52 mark[str[i]] = 1; 53 swap(str[i], str[from]); 54 Permutation(str, from + 1, to); 55 swap(str[i], str[from]); 56 } 57 return; 58 }
时间: 2024-10-10 07:01:27