40. 组合总和 II
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
回溯、剪枝
class Solution {
private void backtracking(List<Integer> temp, List<List<Integer>> result, int start, int target, boolean[] visited, int[] candidates) {
if (target == 0) {
result.add(new ArrayList<>(temp));
}
for (int i = start; i < candidates.length; ++i){
if (i != 0 && candidates[i] == candidates[i - 1] && !visited[i - 1]) { // 去重加剪枝
continue;
}
if (candidates[i] <= target) {
temp.add(candidates[i]);
visited[i] = true;
backtracking(temp, result, i + 1, target - candidates[i], visited, candidates);
visited[i] = false;
temp.remove(temp.size() - 1);
} else { // 剪枝
break;
}
}
}
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(candidates);
backtracking(new ArrayList<>(), result, 0, target, new boolean[candidates.length], candidates);
return result;
}
}
216. 组合总和 III
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:
所有数字都是正整数。
解集不能包含重复的组合。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
回溯算法
class Solution {
private void backtracking(List<List<Integer>> result, List<Integer> temp, int k, int n, int start) {
if (temp.size() == k && n == 0) {
result.add(new ArrayList<>(temp));
return;
}
if (temp.size() > k) {
return;
}
for (int i = start; i <= 9; ++i) {
if (i <= n) {
temp.add(i);
backtracking(result, temp, k, n - i, i + 1);
temp.remove(temp.size() - 1);
} else {
break;
}
}
}
public List<List<Integer>> combinationSum3(int k, int n) {
List<List<Integer>> result = new ArrayList<>();
backtracking(result, new ArrayList<>(), k, n, 1);
return result;
}
}
78. 子集
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
回溯算法
class Solution {
private void backtracking(List<List<Integer>> result, List<Integer> temp, int[] nums, int size, int start) {
if (temp.size() == size) {
result.add(new ArrayList<>(temp));
return;
}
for (int i = start; i < nums.length; ++i) {
temp.add(nums[i]);
backtracking(result, temp, nums, size, i + 1);
temp.remove(temp.size() - 1);
}
}
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
for (int i = 0; i <= nums.length; ++i) {
backtracking(result, new ArrayList<>(), nums, i, 0);
}
return result;
}
}
90. 子集 II
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
回溯算法
class Solution {
private void backtracking(List<List<Integer>> result, List<Integer> temp, boolean[] visited, int[] nums, int start, int size) {
if (temp.size() == size) {
result.add(new ArrayList<>(temp));
return;
}
for (int i = start; i < nums.length; ++i) {
if (i != 0 && nums[i] == nums[i - 1] && !visited[i - 1]) {
continue;
}
temp.add(nums[i]);
visited[i] = true;
backtracking(result, temp, visited, nums, i + 1, size);
visited[i] = false;
temp.remove(temp.size() - 1);
}
}
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
List<Integer> temp = new ArrayList<>();
for (int i = 0; i <= nums.length; ++i) {
backtracking(result, temp, new boolean[nums.length], nums, 0, i);
}
return result;
}
}