算法核心
for循环中,处理节点 放一些和回溯中间变量相关的操作,然后在第三步的回溯操作中,对处理节点的操作做回溯处理
void backtracking(参数) {
if (终⽌条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩⼦的数量就是集合的⼤⼩)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
联系
leetcode_22
括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合
思路
主要思路还是上面的方法。
终止条件分为两种,一种是列举完所有的括号后,将结果存入到最终的集合中;因为这里要求了合法结果,所以还有一个判断的过程,这里的合法很好判断,左括号大于等于右括号的数量,则一定合法。
循环没有使用for循环,因为只有左右两种,所以穷举了出来,配合两个计数变量。 穷举时,先左后右,处理结果、递归和回溯,这三步不变。
储存中间变量用的集合是栈,方便回溯。
List<String> result = new ArrayList<>();
public List<String> generateParenthesis(int n) {
// 这里的参数使用栈,方便回溯
backtracking(n, n, new Stack<>());
return result;
}
public void backtracking(int left, int right, Stack<Character> stack) {
// 剩余的左括号数量更大的话,则不合法,直接退出
if (left > right) {
return;
}
// 所有情况都列举完,也直接推出
if (left == 0 && right == 0) {
result.add(toString(stack));
}
// 插入左
if (left > 0) {
stack.push('(');
backtracking(--left, right, stack);
stack.pop();
left++;
}
// 插入右
if (right > 0) {
stack.push(')');
backtracking(left, --right, stack);
stack.pop();
right++;
}
}
public String toString(Stack<Character> stack) {
StringBuilder sb = new StringBuilder();
stack.stream().forEach(item -> sb.append(item));
return sb.toString();
}
leetcode_39
class Solution {
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
for (int i = 0; i < candidates.length; i++) {
List<Integer> start = new ArrayList<>();
start.add(candidates[i]);
back(start, candidates[i], target, i, candidates);
}
return result;
}
public void back(List<Integer> list, int sum, int target, int currentIndex, int[] candidates) {
if (sum > target || candidates[currentIndex] > target) {
return;
}
if (sum == target) {
result.add(new ArrayList<>(list));
return;
}
for (int i = currentIndex ; i < candidates.length; i++) {
sum += candidates[i];
list.add(candidates[i]);
back(list, sum, target, i, candidates);
sum -= candidates[i];
list.remove(list.size() - 1);
}
}
}