排列组合【转】

(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 上(可以改写成≤的形式),其算法步骤如下:

  1. 输出序列本身
  2. 从右至左找到第一个a_j,使得a_j < a_{j+1}且a_{j+1} > a_{j+2} > ... > a_n
  3. 在a[j+1..n]中找到最小的a_k使得a_j < a_k,交换a_j和a_k
  4. 将a[j+1..n]逆序,输出当前序列
  5. 重复第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  

posted @ 2014-04-08 14:48  linyx  阅读(234)  评论(0编辑  收藏  举报