今天,遇到一个同事的问题,要求给定从给定的5个不重复的数字中,取出3个数字,输出所有的组合情况。其实就是数学中的组合问题。以前仅仅做的是关于求出组合的情况数,这个很简单,用递归就可以求解。这题要求列举出所有情况。在网上进行一阵狂搜,最后找到了一个比较好理解的算法,叫“二进制置换算法”,先姑且这样叫吧。算法思想如下:
1、先定义一个数组,用1和0进行组合。其中1和0的总数为5个(即M),1表示命中(或被选中),所以1的总数为3(N)个。
2、那么初始状态可以设置为11100,称为一个状态码。
3、对初始状态是5选3的一种状态,再对这种状态进行后续分析。
4、分析如下:
a.从左到右,遇到第一次出现的10组合时,将其置为01。
b.判断最左边的第1位,如果为1,继续重复a步骤。如果为0,则将置换点之前的1移动到最左边。然后,再重复a步骤。
c.所有情况置换结束的条件是不再出现10组合,即表示已经得到了所有的情况。
5、根据第4步得到的所有状态码进行分析,将所有为1的位置,输出数组中对应的信息,即可得到一个数组的所有情况。
例如:
1 1 1 0 0
1 1 0 1 0
1 0 1 1 0
0 1 1 1 0
1 1 0 0 1
1 0 1 0 1
0 1 1 0 1
1 0 0 1 1
0 1 0 1 1
0 0 1 1 1//该状态码中不再出现10信息,即置换结束
代码如下:
public class Util {
//构造2进制字符串
public static String stringConstruction(int m,int n){
String testsString="";
for(int i=1;i<=m;i++){
if(i>n)
testsString=testsString+"0";
else
testsString=testsString+"1";
}
return testsString;
}
//二进制置换算法
public static List<String> allConditons(String s){
List<String> list = new ArrayList<String>();
list.add(s);
//;
while(true){
int length = list.size()-1;
//标志位
int flag = list.get(length).indexOf("10");
if(flag<0)
break;
//先取最后一个元素
String last =list.get(length);
//判断该元素第1位字符
if(last.indexOf("0")>0){
list.add(last.replaceFirst("10", "01"));
}
else {
//先将10变成01
String ss = last.replaceFirst("10", "01");
//将10前面的内容反置
String before = last.substring(0,last.indexOf("10"));
StringBuffer sb = new StringBuffer(before);
String after=sb.reverse().toString();
list.add(ss.replaceFirst(before, after));
}
}
return list;
}
//通过置换算法获取自由组合
public static List<String> result(String[] r,List<String> list){
List<String> ttList =new ArrayList<String>();
for(int i=0;i<list.size();i++){
String eleString = list.get(i);
String temp="";
for(int j=0;j<eleString.length();j++){
if(eleString.charAt(j)=='1')
temp=temp+r[j]+" ";
}
ttList.add(temp);
}
//ttList去重操作,通过HashSet去重
HashSet<String> hs = new HashSet<String>(ttList);
ttList.clear();
ttList.addAll(hs);
return ttList;
}
}