回溯模板:
void backtracking(){
if(终止条件) {
收集结果
return
}
for(集合的元素集,类似子节点的个数){
处理结点
递归函数
回溯操作(撤销处理结点12, 2撤销 ,13 撤销3, 14)
}
}
何时要startindex?(在组合的情况下)
假设是全组合的话不需要start_index,例如2对应abc,3对应def,23就有九种组合
假设是部分组合的话需要start_index,例如和为5,23和32是同样的
如何记录是否使用过?
定义一个int[] 数组,名称为visited
如果visited[i] == 1,则continue
如果不为1,进行长正常的处理、递归、回溯操作(回溯部分更改visited[i] = 0)
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
示例 1:
输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。
示例 2:
输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]
示例 3:
输入: candidates = [2], target = 1
输出: []
class Solution {
public ArrayList<Integer> combine = new ArrayList<>();
public ArrayList<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
backtracking(0, target, candidates);
return result;
}
public void backtracking(int index, int target,int[] candidates){
if(index == candidates.length){
return;
}
if (target == 0){
ArrayList<Integer> list = new ArrayList<>(combine);
result.add(list);
return;
}
backtracking(index+1, target, candidates);
if(target - candidates[index] >= 0){
combine.add(candidates[index]);
target -= candidates[index];
backtracking(index, target, candidates);
combine.remove(combine.size()-1);
}
}
}
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
class Solution {
ArrayList<List<Integer>> result = new ArrayList<>();
ArrayList<Integer> temp = new ArrayList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
backtrace(0, candidates, target, 0);
return result;
}
public void backtrace(int index, int[] candidates, int target, int sum){
if(target == sum){
ArrayList<Integer> list = new ArrayList<>(temp);
result.add(list);
}
for(int i = index; i < candidates.length; i++){
if(i > index && candidates[i] == candidates[i-1]){
continue;
}
int rs = candidates[i] + sum;
if(rs <= target){
temp.add(candidates[i]);
backtrace(i+1, candidates, target, rs);
temp.remove(temp.size()-1);
}else{
break;
}
}
}
}
找出所有相加之和为 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 {
public ArrayList<List<Integer>> result = new ArrayList<>();
public ArrayList<Integer> list = new ArrayList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
backtracing(n, 1, k);
return result;
}
public void backtracing(int n, int begin,int k){
if(n == 0 && list.size() == k){
result.add(new ArrayList<>(list));
return;
}
for(int i = begin; i <= 9; i++){
if(n > 0){
list.add(i);
backtracing(n-i, i+1, k);
list.remove(list.size()-1);
}
}
}
}
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:
输入:n = 1
输出:["()"]
这里注意backtracing()里面分别判断left和right
left的条件是小于n
right的条件是小于left
class Solution {
ArrayList<String> result = new ArrayList<>();
StringBuilder stringbuilder = new StringBuilder();
public List<String> generateParenthesis(int n) {
backtracing(0, 0, n);
return result;
}
public void backtracing(int left, int right, int n){
if(right == n && left == right){
result.add(stringbuilder.toString());
}
if(left < n){
stringbuilder.append('(');
backtracing(left+1, right, n);
stringbuilder.deleteCharAt(stringbuilder.length()-1);
}
if(right < left){
stringbuilder.append(')');
backtracing(left, right+1, n);
stringbuilder.deleteCharAt(stringbuilder.length()-1);
}
}
}
46. 全排列(可参考如何通过设置状态,表示是否使用过)
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1]
输出:[[1]]
class Solution {
public ArrayList<List<Integer>> result = new ArrayList<>();
public ArrayList<Integer> list = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
int[] visited = new int[nums.length];
backtracing(nums, visited);
return result;
}
public void backtracing(int[] nums, int[] visited){
if(list.size() == nums.length){
result.add(new ArrayList<>(list));
}
for(int i = 0; i < nums.length; i++){
//检查当前数字有没有被使用过,如果使用过,直接continue
if(visited[i] == 1){
continue;
}
visited[i] = 1;
list.add(nums[i]);
backtracing(nums, visited);
//当前位要换数字了,清空状态
visited[i] = 0;
list.remove(list.size()-1);
}
}
}