简单回溯算法oj
回溯算法先画树形图!!!!!
以下三类题模板基本一样,不同之处只是剪枝的方法。回溯算法剪枝要画出树形图,这样就很清楚哪一步该剪枝,依据其特点剪枝。
模板:
void backtrack(parameters) {
if(满足条件){
//get one answer
record answer;
return;
}
for(解空间树的下一个节点){
backtrack(paramter);
}
}
1、全排列
思路:用一个数组来存储已经搜索过的数据,当遍历的起始位置等于数组长度时,说明找到一个排列。添加到结果集并return
public class permutations {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
//因为回溯算法最后会还原上一步操作,用原数组来存储每一次的结果
dfs(nums,0,nums.length - 1);
return res;
}
public void dfs(int[] nums,int start,int end) {
if(start == end) {
//说明已经走到nums的末尾,找到一个结果
List<Integer> temp = new ArrayList<>();
for(int i = 0; i < nums.length;i++) {
temp.add(nums[i]);
}
res.add(temp);
return;
}
//回溯+递归
for(int i = start; i <= end;i++) {
swap(nums,start,i); //每次交换元素,可以得到两个元素的全排列
//求剩下元素的全排列,如果可以一直递归下去找到结果,那么就会添加结果到结果集中
dfs(nums,start + 1,end);
//不论有没有找到,上面递归跳出后,都会再次交换,将原本交换的两个元素恢复
//即回溯,恢复现场
swap(nums,start,i);
}
}
public void swap(int[] nums,int i,int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
dfs函数的第三个参数没有必要,可以通过原数组计算出来
List<List<Integer>> ans = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
if(nums.length == 0) return ans;
dfs(0,nums); //不用传数组长度,因为本身传入的数组就是原数组,直接可以计算长度
return ans;
}
public void dfs(int n,int[] array) {
if(n == array.length) {
//找到一个解
List<Integer> tmp = new ArrayList<>();
for(int i : array) {
tmp.add(i);
}
ans.add(tmp);
return;
}
for(int i = n; i < array.length;i++) {
swap(n,i,array)