本算法题出自http://www.lintcode.com,算法题【153. 数字组合 II 】。
描述:给出一组候选数字(C)和目标数字(T),找出C中所有的组合,使组合中数字的和为T。C中每个数字在每个组合中只能使用一次。
样例
给出一个例子,候选数字集合为[10,1,6,7,2,1,5] 和目标数字 8 ,
解集为:[[1,7],[1,2,5],[2,6],[1,1,6]]
我的解答思路:
1.原数组num进行排序
2.对排序后数组,定位求和的最大下标位置num[max]<=求和值
3.顺序从数组中取一个元素(下标范围为0-max),假设当前下标为x,则将剩余x-max下标作为一个新数组int[max-x],剩余需求和值为target-num[x],以这个新数组和剩余和值,进行步骤1-3的迭代后,得出子序列集合,将子序列集合循环,并和int[x]求和,和值为target的组合为解集
上代码:
public List<List<Integer>> combinationSum2(int[] num, int target) {
// write your code here
List<List<Integer>> list = new ArrayList<>();
//偷个懒,用jdk自带方法排序
Arrays.sort(num);
int maxIndex = 0;
//定位最大下标值
for(maxIndex = 0;maxIndex<num.length;maxIndex++){
if(num[maxIndex] > target) break;
}
for(int i=0;i<maxIndex;i++){
int[] sub = new int[maxIndex-i-1];
//取出一个元素,并将该元素后到最大下标元素作为子数组
System.arraycopy(num,i+1,sub,0,maxIndex-i-1);
if(target>num[i]){
//递归获取剩余和值得可能组合
List<List<Integer>> subcalllist = combinationSum2(sub,target-num[i]);
for(List<Integer> item:subcalllist){
int sum = num[i];
List<Integer> sulist = new ArrayList<>();
sulist.add(num[i]);
for(Integer itemint:item){
sulist.add(itemint);
sum+=itemint;
}
//将取出元素和递归获取的组合挨个验算,和值等于target为结果之一
if(sum == target) list.add(sulist);
}
} else {
//和值与元素值相等的情况,直接放入结果集
List<Integer> sublist = new ArrayList<>();
sublist.add(num[i]);
list.add(sublist);
}
//如果下一个元素值与当前元素值相等,略过(因为这种情况下,根据下一个元素值得出的排列组合必为当前元素值排列组合的子集)
while(i+1 < maxIndex && num[i] == num[i+1]){
i++;
}
}
return list;
}
PS:这是一个简单粗暴的解答方式,似乎并非最优解法