n之中的所有m元素的逆字典序排列组合

来源:互联网 发布:淘宝网官网下载最新版 编辑:程序博客网 时间:2024/06/05 11:43

问题描述

题目原型大概如下:

学校要评优秀学生,有十个平时都很优秀的学生,他们之间不相上下,但是评选的名额有限,假设学生人数是 n (0 < n <= 10) , 评选的名额数时m(0< m <= n),那么希望随机从n名学生中选出m个学生,并且按字典序的列出所有可能的获得优秀的学生名额。n个学生的序号时从 1…n。

示例

输入:

5 2

输出:

54
53
52
51
43
42
41
32
31
21

思路

假设n个学生的序号是[1,2,…,n],从中选m个学生,我们生成一个长度为m的数组,记录选学生的序号索引,例如n=5,m=2,那么index=[0,1]是一开始的选择学生的索引,index=[n-m,n-m+1]=[3,4]是最后一种情况,这里说明一下如何通过index数组求出编号,因为开始我们是从最小索引开始,那么用n-index[i] (0<=i

代码

//注意end index中保存的索引时相对于n来说的范围时[0,1,...,n-2,n-1]public void getAllCase(int n,int m){  if(n<=0 || m<=0 || m>n)    return;  int end[] = new int[m];  //选中的m学生对应的末尾索引  int index[] = new int[m];//当前选中的m个学生的索引值  //初始化end  和 index  for (int i = 0; i < m; i++) {    end[i] = n - m + i;//计算第i个选中的学生能到达的末尾索引    index[i] = i;   }  int l = m - 1;//第m个学生(最后一个学生)对应于m的索引  while (true) {    print(index, n, m);    index[l]++; //每次都是第m个学生的索引值加一(最后一个)    if (index[l] > end[l]) { //超过他自己本来只能到达的最大索引,说明需要进行下一轮      int t = l;      //找到l位置之前已经达到末尾位置的第一个没有到达对应末尾位置的的下标      while (t >= 0 && index[t] >= end[t]) {        t--;      }      //如果t大于等0说明上面while循环要找到的位置时存在的      if (t >= 0) {        int s = index[t];//上一步找到的第一个没有到达对应末尾位置的元素(从右往左)对应于n的索引值。        //从t到m-1除的元素索引加一(相当于后移一位,依次排列在t之后,注意:第一次的t位置就已经开始加一)        while (t < m) {          index[t++] = ++s;        }      } else {//否则说明说明位置都已经到达末尾,既是所有情况都已经遍历了一次        break;      }    }  }}//根据当前的索引数组答应选中的学生序号,因为索引数组时从0开始的,那么n-index[i]恰好得到对应的序号private  void print(int index[], int n, int m) {  for (int i = 0; i < m; i++) {    System.out.print(n - index[i]);  }  System.out.println();}
0 0