Combination Sum系列
第一题是基础,给定一个数组和一个target,求有多少种组合可以加成target。运用回溯法,注意,每次add进结果里的数组需要new
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res=new ArrayList<List<Integer>>();
List<Integer> temp=new ArrayList<>();
Arrays.sort(candidates);
helper(candidates,target,res,temp,0);
return res;
}
public void helper(int[]nums,int target,List<List<Integer>> res,List<Integer>temp,int start){
if(target==0){
res.add(new ArrayList<Integer>(temp));
return;
}
for(int i=start;i<nums.length;i++){
if(nums[i]<=target){
temp.add(nums[i]);
helper(nums,target-nums[i],res,temp,i);
temp.remove(temp.size()-1);
}
if(nums[i]>target){
return;
}
}
}
}
第二题,不能重复使用数组元素,添加去重条件
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> res=new ArrayList<List<Integer>>();
List<Integer> temp=new ArrayList<>();
Arrays.sort(candidates);
helper(candidates,target,res,temp,0);
return res;
}
public void helper(int[]nums,int target,List<List<Integer>> res,List<Integer>temp,int start){
if(target==0){
res.add(new ArrayList<Integer>(temp));
return;
}
for(int i=start;i<nums.length;i++){
if (i > start && nums[i-1] == nums[i]) continue;//前一个等于后一个
if(nums[i]<=target){
temp.add(nums[i]);
helper(nums,target-nums[i],res,temp,i+1);
temp.remove(temp.size()-1);
}
if(nums[i]>target){
return;
}
}
}
}
第三题,1-9中用k个数字加成n,类似上面,判断条件中加上元素个数判断
class Solution {
public List<List<Integer>> combinationSum3(int k, int n) {
List<List<Integer>> ans = new ArrayList<>();
combination(ans, new ArrayList<Integer>(), k, 1, n);
return ans;
}
private void combination(List<List<Integer>> ans, List<Integer> comb, int k, int start, int n) {
if (comb.size() == k && n == 0) {
List<Integer> li = new ArrayList<Integer>(comb);
ans.add(li);
return;
}
for (int i = start; i <= 9; i++) {
comb.add(i);
combination(ans, comb, k, i+1, n-i);
comb.remove(comb.size() - 1);
}
}
}
第四题与前三题都不太一样,因为不同的顺序也算一种,只需要输出结果数。
nums = [1, 2, 3]
target = 4The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
使用递归,记忆数组加速,而且不需要start来标注起点。
class Solution {
public int combinationSum4(int[] nums, int target) {
int[] memo=new int[target+1];
Arrays.fill(memo,-1);
return helper(nums,target,memo);
}
public int helper(int[]nums,int target,int[] memo){
if (target == 0) {
return 1;
}
if(memo[target]!=-1){
return memo[target];
}
int res = 0;
for (int i = 0; i < nums.length; i++) {
if (target >= nums[i]) {
res += helper(nums, target - nums[i],memo);
}
}
memo[target]=res;
return res;
}
}
回溯法要点在于确定一个起点,往下递归,递归完成后恢复成上一步。