排列组合【转】
(1) 全排列:
将数组看为一个集合,将集合分为两部分:0~s和s~e,其中0~s表示已经选出来的元素,而s~e表示还没有选择的元素。
perm(set, s, e)
{
顺序从s~e中选出一个元素与s交换(即选出一个元素)
调用perm(set, s + 1, e)
直到s>e,即剩余集合已经为空了,输出set
}
1 void perm(int list[], int s, int e, void (*cbk)(int list[])) 2 { 3 int i; 4 if(s > e) 5 { 6 (*cbk)(list); 7 } 8 else 9 { 10 for(i = s; i <= e; i++) 11 { 12 swap(list, s, i); 13 perm(list, s + 1, e, cbk); 14 swap(list, s, i); 15 } 16 } 17 }
排列的非递归算法:
L算法作用于有序序列a_1 < a_2 < a_3 < ... < a_n 上(可以改写成≤的形式),其算法步骤如下:
- 输出序列本身
- 从右至左找到第一个a_j,使得a_j < a_{j+1}且a_{j+1} > a_{j+2} > ... > a_n
- 在a[j+1..n]中找到最小的a_k使得a_j < a_k,交换a_j和a_k
- 将a[j+1..n]逆序,输出当前序列
- 重复第2~5步,直到找不到第二步中合适的a_j
这种算法可以生成字典序的排列序列。
1 public static IEnumerable<T[]> FullPermutations<T>(IEnumerable<T> iter) where T : IComparable<T> 2 { 3 var pool = iter.ToArray(); 4 while (true) 5 { 6 yield return pool.ToArray(); 7 int j = pool.Length - 2; 8 while (j >= 0 && pool[j].CompareTo(pool[j + 1]) >= 0) 9 { 10 j--; 11 } 12 if (j < 0) 13 yield break; 14 int k = pool.Length - 1; 15 while (k > j && pool[k].CompareTo(pool[j]) <= 0) 16 { 17 k--; 18 } 19 SwapItem(pool, j, k); 20 Reverse(pool, j + 1, pool.Length - 1); 21 } 22 } 23 private static void Reverse<T>(IList<T> lst, int s, int e) 24 { 25 while (s < e) 26 { 27 Swap(lst, s, e); 28 s++; 29 e--; 30 } 31 }
(2)组合
组合指从n个不同元素中取出m个元素来合成的一个组,这个组内元素没有顺序。使用C(n, k)表示从n个元素中取出k个元素的取法数。
每一次从集合中选出一个元素,然后对剩余的集合(n-1)进行一次k-1组合。反向地选取。
1 class Solution { 2 public: 3 vector<vector<int> > combine(int n, int k) { 4 vector<int> r(k, 0); 5 recursive(n, k, r); 6 return ret; 7 } 8 9 void recursive(int n, int k, vector<int> &r) { 10 if (k <= 0) { 11 ret.push_back(r); 12 return; 13 } 14 for (int i = n; i >= k; --i) { 15 r[k - 1] = i; 16 recursive(i - 1, k - 1, r); 17 } 18 } 19 20 private: 21 vector<vector<int> > ret; 22 };
组合的非递归实现:
首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。
然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为
“01”组合,同时将其左边的所有“1”全部移动到数组的最左端。
当第一个“1”移动到数组的m-n的位置,即n个“1”全部移动到最右端时,就得
到了最后一个组合。
例如求5中选3的组合:
1 1 1 0 0 //1,2,3
1 1 0 1 0 //1,2,4
1 0 1 1 0 //1,3,4
0 1 1 1 0 //2,3,4
1 1 0 0 1 //1,2,5
1 0 1 0 1 //1,3,5
0 1 1 0 1 //2,3,5
1 0 0 1 1 //1,4,5
0 1 0 1 1 //2,4,5
0 0 1 1 1 //3,4,5