参考这篇博客的方法http://blog.youkuaiyun.com/randyjiawenjie/article/details/6784355
方法思路:用一个位数组来表示组合数的一种组合情况。比如C(n,m),m个数里面,n个数的不同组合情况。可以表示成11..100...0其中1的个数代表这个数字出现在组合中,0所在的位数代表这个数字没有出现在组合中。比如,C(3,5),对于数字1到5来说,其中一种组合情况就是123,表示成位数组就是11100;另一种组合情况,比如134,表示成10110。现在通过有规律的移动每一位上的1,来找出所有的排列数,比如C(3,5)
那篇博客里给出的描述不是很清晰,我再用自己的语言描述一下,加深记忆。首先从11100开始,从左到右寻找10组合,如果找到一个10组合,就将两个位置上的1和0调换位置。并且,对于新调换位置后的那个1,对他前面的子数组里的各位元素,重复从左到右寻找10组合的过程,并调换。重复这个过程,直到子数组里不再有10组合,则向上返回,继续探测父数组的10组合,发现后,再对新交换的1前面的子数组进行探测,知道找到所有情况。
乍一看这个方法,就是一个寻找10组合并置换的方法,但他有个恼人的地方,就是原数组置换之后,只能对置换的那个1前面的子数组置换。一开始没有看清这个子数组的关系,输出的结果有很多重复项,后来增加了一个位置标记,用来告诉下一次调用,循环探测到哪个位置停止,结果就正常了。
下面是用迭代的方法的实现
import java.util.ArrayList;
public class TEST{
public static ArrayList<ArrayList<Integer>> alllist = new ArrayList<ArrayList<Integer>>();
public static void main(String[] args){
System.out.println("test:");
int m = 6;
int n = 3;
ArrayList<Integer> arr = new ArrayList<Integer>();
for(int i = 0; i< m; i++){
arr.add(0);
}
for(int i = 0; i< n; i++){
arr.set(i, 1);
}
rearrange(arr, m);
for(int i = 0; i< alllist.size(); i++){
for(int j= 0; j< alllist.get(i).size(); j++){
System.out.print(alllist.get(i).get(j));
System.out.print(",");
}
System.out.println();
}
}
public static void rearrange(ArrayList<Integer> arr, int m){
ArrayList<Integer> ins;
ins = new ArrayList<Integer>();
ins.addAll(arr);
alllist.add(ins);
for(int i = 1; i< m; i++){
if(arr.get(i-1)== 1 && arr.get(i)== 0){
ins = new ArrayList<Integer>();
arr.set(i-1, 0);
arr.set(i, 1);
ins.addAll(arr);
rearrange(ins, i);
}
}
return;
}
}