DESC:
题目描述
给出一组候选数 C和一个目标数 T,找出候选数中起来和等于 T 的所有组合。
C中的每个数字在一个组合中只能使用一次。注意:
- 题目中所有的数字(包括目标数 T\ T T )都是正整数
- 组合中的数字 (a1,a2,…,ak) 要按非递增排序 (a1≤a2≤…≤ak).
- 结果中不能包含重复的组合
- 组合之间的排序按照索引从小到大依次比较,小的排在前面,如果索引相同的情况下数值相同,则比较下一个索引。
示例1
输入
[100,10,20,70,60,10,50],80
返回值
[[10,10,60],[10,20,50],[10,70],[20,60]]
说明
给定的候选数集是[100,10,20,70,60,10,50],目标数是80
CODE:
JAVA:
import java.util.*; public class Solution { public ArrayList<ArrayList<Integer>> combinationSum2(int[] num, int target) { ArrayList<ArrayList<Integer>> res = new ArrayList(); if (num == null || num.length == 0) { return res; } Arrays.sort(num); ArrayList<Integer> valList = new ArrayList(); backTrack(res, 0, valList, 0, num, target); return res; } private void backTrack(ArrayList<ArrayList<Integer>> res, int start, ArrayList<Integer> valList, int sum, int[] num, int target){ if (sum == target) { res.add(new ArrayList<>(valList)); return; } if (start >= num.length) { return; } //注意从start开始,不同于abc,bac组合,这里为和 for (int i=start; i< num.length; i++) { if (i>start && num[i] == num[i-1]) { continue; } valList.add(num[i]); sum += num[i]; //剪枝,后面不需要再遍历,肯定都大,因为数组是递增 if (sum > target) { valList.remove(valList.size()-1); break; } backTrack(res, i+1, valList, sum, num, target); sum -= num[i]; valList.remove(valList.size()-1); } } }
NOTES:
- 回溯法,但要注意去重条件,如123,213是不同组合,但和是一样的,且结果要求递增,123,213->123是重复的结果,所以不同于“有重复数字的所有排列”需求条件;
- 迭代中可以剪枝,但结果超过sum,后面的路径就不需要查找了,肯定都大于目标值;
- 迭代中,下一队列要冲上一队列的索引+1开始,避免重复,如【10,20,30,40】,第一队列为20,则下一队列从30开始迭代,就可避免ab,ba这种重复;
- 重复数字问题和“有重复数字的所有排列”解决方法思想一致
题目2:
描述
给定一个无重复元素的正整数数组 nums 和一个正整数 target ,找出 nums 中所有可以使数字之和为目标数 target 的组合,nums 中的数可以重复选取,只要选出的组合中有一个数不同则视为是不同组合。
数据范围:数组长度满足 1≤���(����)≤30 1≤len(nums)≤30 , 数组中的元素满足 1≤���≤200 1≤val≤200 ,1≤������≤500 1≤target≤500 ,保证组合数结果少于 150 个
示例1
输入:
1,[1]复制返回值:
[[1]]复制
示例2
输入:
5,[1,4,5]复制返回值:
[[1,4],[5],[1,1,1,1,1]]复制
示例3
输入:
5,[2]复制返回值:
[]
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param target int整型
* @param nums int整型一维数组
* @return int整型ArrayList<ArrayList<>>
*/
public ArrayList<ArrayList<Integer>> combinationCount (int target, int[] nums) {
// write code here
if (nums == null || nums.length == 0) {
return new ArrayList<>(0);
}
Arrays.sort(nums);
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
ArrayList<Integer> temp = new ArrayList<>();
combinationCount(nums, res, temp, target, 0, 0);
return res;
}
public void combinationCount(int[] nums, ArrayList<ArrayList<Integer>> res, ArrayList<Integer> temp, int target, int sum, int start) {
if (sum == target) {
res.add(new ArrayList<Integer>(temp));
return;
}
if (start >= nums.length || sum > target) {
return;
}
for (int i=start; i<nums.length; i++) {
// if (i>0 && nums[i] == nums[i-1]) {//题目限定无重复元素
// continue;
// }
int val = nums[i];
sum += val;
if (sum > target) {
// sum -= val;
break;
}
temp.add(val);
combinationCount(nums, res, temp, target, sum, i);//元素可重复选取,i无需加1,示例target=2,nums=[1],答案是【1,1】
// combinationCount(nums, res, temp, target, sum, i+1);
sum-=val;
temp.remove(temp.size()-1);
}
}
}