算法之数学自由组合问题(从M个不重复的数字中选取N个数字进行自由组合)

今天,遇到一个同事的问题,要求给定从给定的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;
		}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值