描述
回溯其实就是暴力搜索,其思路是dfs。
回溯法思路的简单描述是:把问题的解空间转化成了图或者树的结构表示,然后使用**深度优先搜索策略**进行遍历,遍历的过程中记录和寻找所有可行解或者最优解。
分类
解空间树分为两种:**子集树和排列树**。两种在算法结构和思路上大体相同。
排列就是遍历所有空间,需要标记是否遍历过;for(i=0)
组合和子集其实是一类问题,只用遍历同一层还没遍历的,因此可以省去标记,for(i=start)
不同的是子集问题是,只要遍历一个点,就将当前符合要求的路径添加到最终答案中。
回溯法模板:
1 | void backtrack(参数) { |
对于需要去重的回溯问题:
(1)排列:
for(int i = 0; i < nums.length; i++){
//若在同一层已经遍历过(就是循环过了),则跳过这次
if(i > 1 && nums[i] == nums[i-1] && !used[i - 1]) continue;
(2)子集和组合:
for(inti=start;i<nums.length;i++){
if(i>start&&nums[i]==nums[i-1])continue;
题目
当问题是要求满足某种性质(约束条件)的所有解或最优解时,往往使用回溯法。
它有“通用解题法”之美誉。
- 子集问题lc78,lc90
- 排列问题lc46,lc47
- 组合求和问题lc39,40,216
- 分割回文串lc131
- 阿里快递最短路alibaba(DFS)
- 组合问题lc77【lc77中有对回溯法的优化,即剪枝】,lc401
- 二维平面上使用回溯法 lc79
- floodfill lc200(岛屿的个数),130,417
- N皇后问题lc51
- 数独问题lc37