优化后的组合算法

        项目中一个算法中涉及到了组合,大概业务是:给定一个值X,从n个数中找出能组合加起来和X相等的集合。如果用通常的组合算法,数量级是2的n的阶乘,如果记录比较多的话,有效率问题。我针对我们的业务,优化写了一个算法。

       大概逻辑:先给n个值从小到大排序形成一个队列,组合数从2开始依次递增,每次执行一个剔除操作,假设组合数递增到m,取队列中前面m-1个连续的值,并加上最大的一个值V,如果大于X,那么舍弃V。这样队列是不断缩小的。舍弃无用的组合,运算量也会大大减少。具体见代码:

/**
	 * 从list中找出金额可以凑出db的多个lend2match
	 * list需要根据金额从小到大排序
	 * @param listLend  list,需要凑的金额,几个出借人组合数量(第一次从2开始),开始的序号(第一次为0)
	 * @param db
	 */
	
	public static List<Lend2match> makeUp(List<Lend2match> listLend,Double db ,int num,int index) {
		if (num>listLend.size()) {
			//数量超出,整个list中没有合适的组合
			return null;
		}
		//记录合适的makeup
		List<Lend2match> listMakeUp=new ArrayList<Lend2match>();
		
		List<Lend2match> listReturn=new ArrayList<Lend2match>();
		
		double dbMakeUp=0;
		//计算出最小的几个值,预留一个空缺
		for (int i = 0; i <num-1; i++) {
			dbMakeUp+=listLend.get(i+index).getLendAmount();
			listMakeUp.add(listLend.get(i+index));//先存起来记录
		}
		Double tmp=dbMakeUp;
		//记录要舍去的list
		List<Lend2match> listDel=new ArrayList<Lend2match>();
		
		for (int i = num+index-1; i < listLend.size(); i++) {
			dbMakeUp+=listLend.get(i).getLendAmount();
			if (dbMakeUp==db) {//正好相等,记录并跳出
				listMakeUp.add(listLend.get(i));
				listReturn=listMakeUp;
				return listReturn;   //只取第一次匹配合适的记录
			}
			if (dbMakeUp>db) {//超出,舍去最大的那个记录
				listDel.add(listLend.get(i));
			}
			dbMakeUp=tmp;//值还原
		}
		//删除要舍去的
		for (Lend2match t:listDel) {
			listLend.remove(t);
		}
		
		//组合遍历
		List<Lend2match> listRec=new ArrayList<Lend2match>();
		listRec=traversal(listLend, listRec, db, num, index);
		if (listRec!=null&&listRec.size()!=0) {
			listReturn=listRec;
		}
		
		
		index++;
		//需要根据新的list,从序号为0开始依次作为组合中最小的
		if (index+num+1>listLend.size()) {
			num++;
			index=0;
		}
		if (listReturn==null||listReturn.size()==0) {
			 //继续迭代,增加组合的数量
			listReturn=makeUp(listLend, db, num,index);
		}
	   
		return listReturn;
	}
	/**
	 * 组合遍历
	 * @param listLend
	 * @param listReturn
	 * @param db
	 * @param num
	 * @param index
	 * @return
	 */
	
	public static List<Lend2match> traversal(List<Lend2match> listLend,List<Lend2match> listReturn,Double db ,int num,int index){
		Double dbTmp=db;
		for (int i = index; i < listLend.size()-1-num; i++) {
			
			db=db-listLend.get(index).getLendAmount();
			if (db==0) {//正好匹配
				listReturn.add(listLend.get(index));
			}else if (db>0) {
				int index1=i+1;
				int num1=num-1;
				listReturn=traversal(listLend,listReturn, db, num1, index1);
				if (listReturn!=null&&listReturn.size()!=0) {
					listReturn.add(listLend.get(index));
				}else {
					listReturn=null;
				}
			}else if (db<0) {
				listReturn=null;
			}	
			db=dbTmp;
		}
		return listReturn;
	}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值