1. 题目
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]
]
2. 题目分析
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。这其实跟硬币找零问题差不多,就是给定一些数值,通过这些数值(元素数量无限)组成固定的数字。
3. 解题思路
题目给了我们一个candidates array 和一个 target, 让我们从array 里找到所有的组合,它的和是等于target的。任何组合只要是它的和等于target的话,都需要找到,但是不需要重复的。这道题中是可以重复利用一个数字的,那么我们就需要每次都代入同一个数字,直到它之和达到target 或者它超过了target, 然后在倒退回去一个数字,继续找下一个数字,这种情况肯定是要用递归了。这里是backtracking,每次倒退回一个数字,需要继续递归下去,在倒退,一直重复直到搜索了所有的可能性。
4. 代码实现(java)
package com.algorithm.leetcode.backtracking;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Created by 凌 on 2019/1/30.
* 注释:39. Combination Sum
*/
public class CombinationSum {
/**
* 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
* @param candidates
* @param target
* @return
*/
public List<List<Integer>> combinationSum(int[] candidates, int target) {
if (candidates == null || target < 0){
return new ArrayList<>();
}
Arrays.sort(candidates);
List<List<Integer>> combineList = new ArrayList<>();
List<Integer> combineCeil = new ArrayList<>();
int start = 0;
dfs(combineList,combineCeil,candidates,target,start);
return combineList;
}
public void dfs(List<List<Integer>> combineList,List<Integer> combineCeil,int[] candidates, int target,int start){
if (target < 0){
return;
}else if (target == 0){
combineList.add(new ArrayList<>(combineCeil));
return;
}else{
for (int i = start; i < candidates.length; i++) {
combineCeil.add(candidates[i]);
dfs(combineList,combineCeil,candidates,target - candidates[i],i);
combineCeil.remove(combineCeil.size()-1);
}
}
}
}
1. 题目
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]
]
2. 题目分析
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字只能被选取一次。
不同点: 不能重复使用同一个位置上的元素,但是不同位置上可能有相同值的元素,所以–>需要考虑重复答案的问题
3. 解题思路
39. Combination Sum && 40. Combination Sum II && 216. Combination Sum III 等回溯问题,其实都是一个套路,都是需要另写一个递归函数,这里我们新加入三个变量,start记录当前的递归到的下标,combineCeil为一个中间解,combineList保存所有已经得到的解,每次调用新的递归函数时,此时:
4. 代码实现(java)
package com.algorithm.leetcode.backtracking;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Created by 凌 on 2019/2/3.
* 注释:40. Combination Sum II
*/
public class CombinationSum2 {
public static void main(String[] args) {
CombinationSum2 combinationSum2=new CombinationSum2();
int[] candidates = {10,1,2,7,6,1,5};
int target = 8;
List<List<Integer>> result = combinationSum2.combinationSum2(candidates,target);
System.out.println(result.toArray());
}
/**
* 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字只能被选取一次。
不同点: 不能使用同一个位置上的元素,但是不同位置上可能有相同值的元素,所以-->需要考虑重复答案的问题
* @param candidates
* @param target
* @return
*/
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
if (candidates == null || target < 0){
return new ArrayList<>();
}
Arrays.sort(candidates);
List<List<Integer>> combineList = new ArrayList<>();
List<Integer> combineCeil = new ArrayList<>();
int start = 0;
dfs(combineList,combineCeil,candidates,target,start);
return combineList;
}
public void dfs(List<List<Integer>> combineList,List<Integer> combineCeil,int[] candidates, int target,int start){
if (target < 0){
return;
}else if (target == 0){
combineList.add(new ArrayList<>(combineCeil));
}else{
for (int i = start; i < candidates.length; i++) {
if (i > start && candidates[i] == candidates[i-1]){
continue;
}
combineCeil.add(candidates[i]);
dfs(combineList,combineCeil,candidates,target - candidates[i],i+1);
combineCeil.remove(combineCeil.size()-1);
}
}
}
}
1. 题目
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]]
2. 题目分析
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
解集不能包含重复的组合。
3. 解题思路
这题其实就是前两题的结合体,给定的数字变成1-9,然后要求找到的组合不存在相同数字。
4. 代码实现(java)
package com.algorithm.leetcode.backtracking;
import java.util.ArrayList;
import java.util.List;
/**
* Created by 凌 on 2019/2/3.
* 注释:216. Combination Sum III
*/
public class CombinationSum3 {
public static void main(String[] args) {
CombinationSum3 combinationSum3=new CombinationSum3();
int k = 3;
int target = 7;
List<List<Integer>> result = combinationSum3.combinationSum3(k,target);
System.out.println(result.toArray());
}
/**
* 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
解集不能包含重复的组合
* @param k
* @param target
* @return
*/
public List<List<Integer>> combinationSum3(int k, int target) {
if (target > 45 || target < 0){
return new ArrayList<>();
}
List<List<Integer>> combineList = new ArrayList<>();
List<Integer> combineCeil = new ArrayList<>();
int start = 1;
dfs(combineList,combineCeil,target,k,start);
return combineList;
}
public void dfs(List<List<Integer>> combineList, List<Integer> combineCeil, int target,int k, int start){
if (target < 0){
return;
}else if (combineCeil.size() == k && target == 0){
combineList.add(new ArrayList<>(combineCeil));
}else{
for (int i = start; i <= 9; i++) {
combineCeil.add(i);
dfs(combineList,combineCeil,target - i, k,i+1);
combineCeil.remove(combineCeil.size()-1);
}
}
}
}