zoukankan      html  css  js  c++  java
  • 排列组合【转】

    (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  

  • 相关阅读:
    广域网(ppp协议、HDLC协议)
    0120. Triangle (M)
    0589. N-ary Tree Preorder Traversal (E)
    0377. Combination Sum IV (M)
    1074. Number of Submatrices That Sum to Target (H)
    1209. Remove All Adjacent Duplicates in String II (M)
    0509. Fibonacci Number (E)
    0086. Partition List (M)
    0667. Beautiful Arrangement II (M)
    1302. Deepest Leaves Sum (M)
  • 原文地址:https://www.cnblogs.com/linyx/p/3651984.html
Copyright © 2011-2022 走看看