1.leetcode 39 Combination Sum
题目描述:
Given a set of candidate numbers (candidates
) (without duplicates) and a target number (target
), find all unique combinations in candidates
where the candidate numbers sums to target
.
The same repeated number may be chosen from candidates
unlimited number of times.
Note:
- All numbers (including
target
) will be positive integers. - The solution set must not contain duplicate combinations.
Example 1:
Input: candidates = [2,3,6,7], target = 7,A solution set is:[[7], [2,2,3]]
Example 2:
Input: candidates = [2,3,5], target = 8,A solution set is:[[2,2,2,2],[2,3,3],[3,5]]
思路:深度优先遍历
1.首先对数组进行排序;
2. 深度优先遍历所有可能解的问题,由于没有设置解集的大小且所有数字都可以重复选取,必须采用能够自动挖掘解集的解法
3. 通过递归的方式对所有可能解集进行遍历。
4.如果加入某个数后导致target-arr[i]小于0,则无需继续遍历,因为数组进行了排序,后面的数比当前数更大,加入后更不会出现为0的结果。这样可以减少一些无用的遍历。
实现1:通用模板解法
一种直观理解的实现方式
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> ret=new ArrayList<>();
Arrays.sort(candidates);
fun(candidates,target,0,ret,new ArrayList<>());
return ret;
}
private void fun(int[] arr,int target,int start,List<List<Integer>> ret,ArrayList<Integer> sub){
if(target<0){
return;
}
if(target==0){
ret.add(new ArrayList<>(sub));
return;
}
for(int i=start;i<arr.length;i++){
sub.add(arr[i]);
fun(arr,target-arr[i],i,ret,sub);
sub.remove(sub.size()-1);
if(target<0){
break;
}
}
return;
}
}
实现2:
思路和实现1一样,但是不知为何执行时间更快
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> ret=new ArrayList<>();
Arrays.sort(candidates);
fun(candidates,target,0,ret,new ArrayList<>());
return ret;
}
private boolean fun(int[] arr, int target, int start, List<List<Integer>> ret, ArrayList<Integer> sub) {
if(target<0) return false;
if(target==0){
ret.add(new ArrayList<>(sub));
return false;
}
for(int i=start;i<arr.length;i++){
sub.add(arr[i]);
boolean flag=fun(arr, target-arr[i], i, ret, sub);
sub.remove(sub.size()-1);
if(!flag){
break;
}
}
return true;
}
}
2. leetcode 40. Combination Sum II
Given a collection of candidate numbers (candidates
) and a target number (target
), find all unique combinations in candidates
where the candidate numbers sums to target
.
Each number in candidates
may only be used once in the combination.
Note:
- All numbers (including
target
) will be positive integers. - The solution set must not contain duplicate combinations.
Example 1:
Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:[[1, 7],[1, 2, 5],[2, 6],[1, 1, 6]]
Example 2:
Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:[[1,2,2],[5]]
思路:
和上一题一样,需要使用递归,不断的加入尝试,不同的是,这个题中元素不能重复使用,所以在递归的时候是i+1而不是i。
另外,因为数组中有重复的元素,但是组合数同一个数只能算一种,所以需要对这种情况进行过滤。
实现1:
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> ret=new ArrayList<>();
ArrayList<Integer> sub=new ArrayList<>();
Arrays.sort(candidates);
fun(candidates,target,0,ret,sub);
return ret;
}
private boolean fun(int[] arr,int target,int start,List<List<Integer>> ret,ArrayList<Integer> sub){
if(target<0){
return false;
}
if(target==0){
ret.add(new ArrayList(sub));
return false;
}
for(int i=start;i<arr.length;i++){
if(i>start&&arr[i]==arr[i-1]){
continue;//过滤掉相同的组合
}
sub.add(arr[i]);
boolean flag=fun(arr,target-arr[i],i+1,ret,sub);
sub.remove(sub.size()-1);
if(!flag){
break;
}
}
return true;
}
}
实现2:通用模板解法
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> ret=new ArrayList<>();
ArrayList<Integer> sub=new ArrayList<>();
Arrays.sort(candidates);
fun(ret,sub,candidates,target,0);
return ret;
}
private void fun(List<List<Integer>> ret,ArrayList<Integer> sub,int[] nums,int target,int start){
if(target==0){
ret.add(new ArrayList<>(sub));
return;
}
if(target<0){
return;
}
for(int i=start;i<nums.length;i++){
if(i>start&&nums[i]==nums[i-1]){
continue;
}
sub.add(nums[i]);
fun(ret,sub,nums,target-nums[i],i+1);
sub.remove(sub.size()-1);
if(target<0){
break;
}
}
}
}
leetcode 216. Combination Sum III
题目描述:
Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
Note:
- All numbers will be positive integers.
- The solution set must not contain duplicate combinations.
Example 1:
Input: k = 3, n = 7 Output: [[1,2,4]]
Example 2:
Input: k = 3, n = 9 Output: [[1,2,6], [1,3,5], [2,3,4]]
思路:
仍然是all possible combinations的题目,所以还是用深度搜索算法,和上面的题目解法一样,从1开始向后不断深度搜索满足条件的答案,若不符合,则移除当前值。
递归需要返回的条件:
1.当k==0且n==0,说明我们找到了满足条件的值,此时将该值加入到ret中并return,继续向后搜索。
2.当k==0,但n!=0,或者n<0,此时说明没有找到符合条件的值,也需要返回。
另外,
返回之后我们需要将最后的数移除并不断向后搜索,但是有一种条件下不需要继续向后遍历,那就是n<=i的情况
比如k=3,n=7,我们已经找到满足条件的子数组【1,2,4】,那么就没有必要向后接着遍历了,因为大于4的数加入list中肯定也比7大了。
实现:
class Solution {
public List<List<Integer>> combinationSum3(int k, int n) {
List<List<Integer>> ret=new ArrayList<>();
if(n<0||k>9){
return ret;
}
ArrayList<Integer> sub=new ArrayList<>();
fun(ret,sub,k,n,1);
return ret;
}
private void fun(List<List<Integer>> ret,ArrayList<Integer> sub,int k,int n,int start){
if(k==0&&n==0){
ret.add(new ArrayList<>(sub));
return;
}
if(k==0&&n!=0||n<0){
return;
}
for(int i=start;i<=9;i++){
sub.add(i);
fun(ret,sub,k-1,n-i,i+1);
sub.remove(sub.size()-1);
if(n<=i){
break;
}
}
}
}
参考: