LeetCode 回溯法 阶段性小结 个人向专题通关计划

回溯

    • 回溯法应用场景
    • 回溯法代码模板
    • 回溯:组合问题
      • LeetCode77 组合
      • LeetCode40 组合总和 II
    • 回溯:切割问题
      • LeetCode131 分割回文串
      • LeetCode93 复原IP地址
    • 回溯:子集问题
      • LeetCode491 递增子序列
    • 回溯:排列问题
      • LeetCode46 全排列
      • LeetCode47 全排列 II
    • 回溯:棋盘问题
      • LeetCode51 N皇后

回溯法应用场景

回溯法又叫回溯搜索法,是一种搜索的方式,类似于深度搜索。回溯搜索的本质是穷举搜索,所以并不是一种高效的算法,可以考虑一些剪枝优化策略。
回溯法可以解决的问题种类一般包括以下几种:

  • 组合问题:N个数里面按照某种要求找出满足条件的k个数的集合
  • 切割问题:一个字符串按照某种要求可以有多少种切割方式
  • 子集问题:一个N个数的集合里有多少符合条件的子集
  • 排列问题:N个数按某种规则全排列,可以有多少种排列方式
  • 棋盘问题:N皇后、解数独等

回溯法代码模板

按照树结构和深度搜索的思想可以较好地理解回溯的过程:

void backtracking(params):{
   
	if(达到终止条件){
   
		记录当前可行的结果; //总的结果池中的一种
		return;
	}
	for(本层集合中元素(也可理解为树节点的孩子个数)){
   
		处理节点;
		backtracking(更新参数); //深搜递归
		回溯:撤销上面的处理结果; //精髓部分
	}
}

注意:节点处理的过程与回溯撤销的过程要一一对应。

回溯:组合问题

LeetCode77 组合

题目链接
LeetCode 回溯法 阶段性小结 个人向专题通关计划_第1张图片
解题思路:可以认为随着for循环的不断进行,搜索空间也在不断变化,最终遍历完整个求解空间。
(遍历包含1的求解空间–>遍历包含2但不含1的求解空间–>遍历包含3但不包含1和2的求解空间–>遍历包含4但不包含1、2、3的求解空间),所遍历的求解空间越来越小,但并不交叉,且最终能合并为完整的求解空间
LeetCode 回溯法 阶段性小结 个人向专题通关计划_第2张图片
AC代码:

class Solution {
   
private:
    vector<vector<int>> res;
    vector<int> path;
    void backtracking(int n, int k, int idx){
   
        if(path.size() == k){
   
            res.push_back(path);
            return;
        }
        for(int j=idx; j<=n; j++){
   
            path.push_back(j);
            backtracking(n, k, j+1);
            path.pop_back();
        }
    }
public:
    vector<vector<int>> combine(int n, int k) {
   
        backtracking(n, k, 1);
        return res;
    }
};

LeetCode40 组合总和 II

题目链接
LeetCode 回溯法 阶段性小结 个人向专题通关计划_第3张图片
解题思路:排序+去重
AC代码:

class Solution {
   
private:
    vector<vector<int>> res;
    vector<int> path;
    void backtracking(vector<int>& nums, int target, int idx, int sum, int depth){
   
        if(sum == target){
   
            res.push_back(path);
            return;
        }
        for(int i=idx; i<nums.size();i++){
   
        	//去重剪枝 例如[2,2,2,5] 第一次考虑时就已经把最多存在3个2的解空间搜索完了
        	//那么最多只存在2个2的解空间自然已经被覆盖了,就无须额外再进行搜索了
            if(i>idx && nums[i] == nums[i-1]){
    
                continue;
            }
            sum+=nums[i];
            if(sum > target){
    // 剪枝
                break;
            }
            path.push_back(nums[i]);
            //注意这里i&

你可能感兴趣的:(蒟蒻的自我救赎之路,LeetCode,C++,阶段性小结,leetcode,回溯)