全排列 3 种方法整理(递归,多路递归,前缀)
关于全排列的问题描述就不再赘述了,这里整理出 3 种求一个集合中所有元素的全排列的方法。
一、递归 n-1 层
处理 n-1 层(n == 1 时返回),对 n-1 层的所有元素进行 “补左”,“补右”,“补中间”三个操作,得到 n 层。
注意 “补中间” 操作可能涉及多个位置。
参考代码:
// 递归
void getPermutation(string arr, int n){
// 出口 当n == 1时,只有一个元素
if(n == 1){
// 使用字符数组辅助
char ch[1];
ch[0] = arr[0];
string temp(ch, 1);
pre.insert(temp);
return;
}
// 处理好n-1层
getPermutation(arr, n-1);
// 对n-1层的每一个元素都按三种不同的组合方式加上新字符arr[n-1]
for(set<string>::iterator it = pre.begin(); it != pre.end(); it++){
string str = *it;
permutationSet.insert(str+arr[n-1]);
permutationSet.insert(arr[n-1]+str);
for(int i = 1; i < str.length(); i++){
permutationSet.insert(str.substr(0, i)+arr[n-1]+str.substr(i));
}
}
// 注意更新pre 以及置零permutationSet
pre = permutationSet;
permutationSet.clear();
}
二、多路递归
利用了回溯的思想,每层对括号中的每一个元素,取出来加入已经选择的集合,这样成为了下一层。
后面的层都遵循这样的逻辑,直到括号内没有元素。
但是需要保留父亲的状态才能得到其他的支路(因为父节点是共享的)
参考代码:
// 回溯 多路递归
void getPermutation(string &arr, int k){
if(k == arr.length()){
permutationSet.insert(arr);
return;
}
for(int i = k; i < arr.length(); i++){
swap(arr[k], arr[i]); // 交换
getPermutation(arr, k+1); // 递归
swap(arr[k], arr[i]); // 回溯
}
}
三、前缀
中括号 [ ] 中的字符串为前缀,每次只要遍历集合查看有哪些字符没有在前缀 prefix 中,
分别加在前缀的后面继续进行递归。
参考代码:
// 前缀 可以求出第几个排列
void getPermutation(string arr, int n, string prefix){
if(prefix.length() == n){
permutationSet.insert(prefix);
return;
}
for(int i = 0; i < n; i++){
if(count(prefix, arr[i]) < count(arr, arr[i])){
getPermutation(arr, n, prefix+arr[i]);
}
}
}
【END】感谢观看