数字组合

给出一个候选数字的集合 C 和目标数字 T,写一个函数找到 C 中所有的组合,使找出的数字和为 T。C 中的数字可以无限制重复被选取。


注意事项:

1、所有的数字(包括目标数字)均为正整数。

2、元素组合(a1, a2, … , ak)必须是非降序(ie, a1 ≤  a2  ≤ … ≤  ak)。

3、解集不能包含重复的组合。 


格式:


输入行每一行输入数组 C 和一个目标数字 T,最后输出所有满足条件的组合


样例输入


C = [ 2,3,6,7 ]

T = 7


样例输出


[ [ 7 ],[ 2,2,3 ] ]

解题思路。

我们先降低规模,假设只有数组array=[1,2]

那么

1=1,没有组合

2 = 1+1 组合为(1,1)

3 = 1+2 = 1+(1+1) 组合为(1,2),(1,1,1)

4 = 1+3              =2+2

   = 1+(1+2)        =(1+1)+2

   = 1+(1+1+1)    =(1+1)+(1+2)

   所以4的组合为(1,1,2),(1,1,1,1),(2,2)。注意(1,3)这个组合是没有的,因为数组array中没有3这个元素

从以上的规律可以得出如下结论:

 假设n = a+b,那么n的组合就是a的组合与b的组合的交叉组合。前提条件是a和b要么在数组array中出现过,要么a、b有自己的组合。

有次我得给出的代码如下:

package suanfa;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

public class NumberCombination {

	public static void main(String[] args) {
		int a[] = new int[] {2, 3, 6, 7,9,13,17,21};
		int t = 20;
		Map<Integer, TreeSet<String>> map = compute(a,t,new HashMap<Integer,TreeSet<String>>());
		
		Iterator<Integer> ite = map.keySet().iterator();
		while(ite.hasNext()){
			int key = ite.next();
			Set<String> value = map.get(key);
			System.out.print("["+String.format("%-"+String.valueOf(t).length()+"s", key));
			for(String str:value){
				System.out.print(",["+str+"]");
			}
			System.out.println("]");
		}
	}
	
	
	public static String strSort(String str){
		List<String> list = Arrays.asList(str.split(","));
		Collections.sort(list,new Comparator<String>(){

			@Override
			public int compare(String arg0, String arg1) {
				if(Integer.parseInt(arg0) >= Integer.parseInt(arg1)){
					return -1;
				}else{
					return 1;
				}
			}
		});
		String s = list.get(0);
		for(int i =1; i< list.size();i++){
			s += ","+list.get(i);
		}
		return s;
	}

	public static Map<Integer, TreeSet<String>> compute(int[] a, int t, Map<Integer, TreeSet<String>> map) {

		for (int i = a[0] + 1; i <= t; i++) {
			boolean is_i_ou = i % 2 == 0;
			int fanwei = is_i_ou ? i / 2 : i / 2 + 1;
			for (int j = i - 1; j >= fanwei; j--) {
				int minus = i - j;
				if (j >= minus) {
					Set<String> comList_minus = map.get(minus);
					Set<String> comList_j = map.get(j);
					boolean exist_minus = isNumberExist(a, minus);
					boolean exist_j = isNumberExist(a, j);
					if ((comList_minus == null && !exist_minus) || (!exist_j&& comList_j == null) ) {
						continue;
					}
					TreeSet<String> compList_i = map.get(i);
					if (compList_i == null) {
						compList_i = new TreeSet<String>(new Comparator<String>(){
							@Override
							public int compare(String arg1, String arg2) {
								String[] str1 = arg1.split(",");
								String[] str2 = arg2.split(",");
								int k = 0;
								for (; k < str1.length && k < str2.length; k++) {
									if (str1[k].length() > str2[k].length() || Integer.parseInt(str1[k]) > Integer.parseInt(str2[k])) {
										return 1;
									}else if(Integer.parseInt(str1[k]) < Integer.parseInt(str2[k])){
										return -1;
									}
								}
								if (str1.length > str2.length) {
									return 1;
								} else if (str2.length > str1.length) {
									return -1;
								} else {
									return 0;
								}
							}
						});
						map.put(i, compList_i);
					}
					
					if (exist_minus && exist_j) {
						compList_i.add(j + "," + minus);
					}
					if (exist_minus && comList_j != null) {
						for (String str : comList_j) {
							compList_i.add(strSort(str + "," + minus));
						}
					}
					if (exist_j && comList_minus != null) {
						for (String str : comList_minus) {
							compList_i.add(strSort(j+","+str + ","));
						}
					}
					if (comList_minus != null && comList_j != null) {
						for (String str1 : comList_minus) {
							for (String str2 : comList_j) {
								compList_i.add(strSort(str1 + "," + str2));
							}
						}
					}
				}
				
			}
		}
		return map;
	}
	

	public static boolean isNumberExist(int[] a, int num) {
		for (int i = 0; i < a.length; i++) {
			if (a[i] == num) {
				return true;
			}
		}
		return false;
	}

}

结果如下:

[4 ,[2,2]]
[5 ,[3,2]]
[6 ,[2,2,2],[3,3]]
[7 ,[3,2,2]]
[8 ,[2,2,2,2],[3,3,2],[6,2]]
[9 ,[3,2,2,2],[3,3,3],[6,3],[7,2]]
[10,[2,2,2,2,2],[3,3,2,2],[6,2,2],[7,3]]
[11,[3,2,2,2,2],[3,3,3,2],[6,3,2],[7,2,2],[9,2]]
[12,[2,2,2,2,2,2],[3,3,2,2,2],[3,3,3,3],[6,2,2,2],[6,3,3],[6,6],[7,3,2],[9,3]]
[13,[3,2,2,2,2,2],[3,3,3,2,2],[6,3,2,2],[7,2,2,2],[7,3,3],[7,6],[9,2,2]]
[14,[2,2,2,2,2,2,2],[3,3,2,2,2,2],[3,3,3,3,2],[6,2,2,2,2],[6,3,3,2],[6,6,2],[7,3,2,2],[7,7],[9,3,2]]
[15,[3,2,2,2,2,2,2],[3,3,3,2,2,2],[3,3,3,3,3],[6,3,2,2,2],[6,3,3,3],[6,6,3],[7,2,2,2,2],[7,3,3,2],[7,6,2],[9,2,2,2],[9,3,3],[9,6],[13,2]]
[16,[2,2,2,2,2,2,2,2],[3,3,2,2,2,2,2],[3,3,3,3,2,2],[6,2,2,2,2,2],[6,3,3,2,2],[6,6,2,2],[7,3,2,2,2],[7,3,3,3],[7,6,3],[7,7,2],[9,3,2,2],[9,7],[13,3]]
[17,[3,2,2,2,2,2,2,2],[3,3,3,2,2,2,2],[3,3,3,3,3,2],[6,3,2,2,2,2],[6,3,3,3,2],[6,6,3,2],[7,2,2,2,2,2],[7,3,3,2,2],[7,6,2,2],[7,7,3],[9,2,2,2,2],[9,3,3,2],[9,6,2],[13,2,2]]
[18,[2,2,2,2,2,2,2,2,2],[3,3,2,2,2,2,2,2],[3,3,3,3,2,2,2],[3,3,3,3,3,3],[6,2,2,2,2,2,2],[6,3,3,2,2,2],[6,3,3,3,3],[6,6,2,2,2],[6,6,3,3],[6,6,6],[7,3,2,2,2,2],[7,3,3,3,2],[7,6,3,2],[7,7,2,2],[9,3,2,2,2],[9,3,3,3],[9,6,3],[9,7,2],[9,9],[13,3,2]]
[19,[3,2,2,2,2,2,2,2,2],[3,3,3,2,2,2,2,2],[3,3,3,3,3,2,2],[6,3,2,2,2,2,2],[6,3,3,3,2,2],[6,6,3,2,2],[7,2,2,2,2,2,2],[7,3,3,2,2,2],[7,3,3,3,3],[7,6,2,2,2],[7,6,3,3],[7,6,6],[7,7,3,2],[9,2,2,2,2,2],[9,3,3,2,2],[9,6,2,2],[9,7,3],[13,2,2,2],[13,3,3],[13,6],[17,2]]
[20,[2,2,2,2,2,2,2,2,2,2],[3,3,2,2,2,2,2,2,2],[3,3,3,3,2,2,2,2],[3,3,3,3,3,3,2],[6,2,2,2,2,2,2,2],[6,3,3,2,2,2,2],[6,3,3,3,3,2],[6,6,2,2,2,2],[6,6,3,3,2],[6,6,6,2],[7,3,2,2,2,2,2],[7,3,3,3,2,2],[7,6,3,2,2],[7,7,2,2,2],[7,7,3,3],[7,7,6],[9,3,2,2,2,2],[9,3,3,3,2],[9,6,3,2],[9,7,2,2],[9,9,2],[13,3,2,2],[13,7],[17,3]]



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值