代码随想录刷题Day49

回溯基本做题理论

  • 回溯本质是穷举,顶多在穷举过程中剪枝
  • 解决排列组合类问题
  • 回溯,可以具象化为树从叶子节点往根节点方向"回去"的过程
  • 回溯三部曲:
    • 返回值(void)和参数
    • 终止条件,达到条件则存放结果并return
    • 回溯搜索的遍历过程
      • 横向:for循环
      • 纵向:递归
cpp 复制代码
void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

组合

回溯的方法,感觉还是有点难上手。我做这一道题,对于回溯三要素:

  • 最开始是不知道如何去有序地罗列 所有情况,看了参考题解,原来是可以选定一个stratIndex来决定。这是回溯的参数确定方面
  • 回溯的终止条件是迭代的深度,也就是数组中数的个数,这个点差点想不到;
  • 回溯的执行逻辑,我自己也没有捋得很明白:
    • for循环执行本层的结果,那下一层结果如何通过递归来实现:原来递归执行下一层操作是基于当前层的,也就是下面代码中的m+1。
    • 以及回溯这个动作需要让数组也跟着pop_back()掉,这样执行完这一层之后,数组中的数目和进入函数前是保持一样的。
cpp 复制代码
class Solution {
public:
    vector<int> v;//存放数组序列
    vector<vector<int>> ans;//存放最后的答案序列
    void backtrack(int n,int k ,int startIndex){
       //从[startIndex,n]中取一个数
        if(v.size()==k){
            //已经收集了k个数
            ans.push_back(v);
            return ;
        }
        for(int m = startIndex;m<=n;m++){
            //取了m这个值
            v.push_back(m);
            //下一层从[m+1,n]中取一个数
            backtrack(n,k,m+1);
            v.pop_back();
        }
    }
    vector<vector<int>> combine(int n, int k) {
        backtrack(n,k,1);
        return ans;
    }
};

回溯虽然有模板算法可以套用,但目前还是比较难自己直接想明白,后面多做题再总结吧。

对于该代码,进一步优化的话,剪枝,主要在循环遍历的时候,m不必循环到n,而是可以根据当前数组中已有数的个数来确定最大取到什么位置。

比如已知现在v还要取t个数就达到有k个数的要求,那么当前这一轮循环m就不用遍历到n,而是遍历到m-t,因为最极限的做法,剩下t个我取[n-t+1,n-t+2,...,n]这t个数的话,m在这样的情况下,应该是最大最大也就是取到n-t,m再往后取,就会出现v还要t个数达到k,但是不够t个数中取t个数。

用中的图解释如下:

代码改动在for循环处:

cpp 复制代码
class Solution {
public:
    vector<int> v;
    vector<vector<int>> ans;
    void backtrack(int n,int k ,int startIndex){
        if(v.size()==k){
            ans.push_back(v);
            return ;
        }
        for(int m = startIndex;m<=n-k+v.size()+1;m++){//for循环处剪枝优化
            v.push_back(m);
            backtrack(n,k,m+1);
            v.pop_back();
        }
    }
    vector<vector<int>> combine(int n, int k) {
        backtrack(n,k,1);
        return ans;
    }
};
相关推荐
语戚3 小时前
力扣 51. N 皇后:基础回溯、布尔数组优化、位运算全解(Java 实现)
java·算法·leetcode·力扣·剪枝·回溯·位运算
小辉同志4 天前
79. 单词搜索
开发语言·c++·leetcode·回溯
xiaoye-duck6 天前
《算法题讲解指南:递归,搜索与回溯算法--综合练习》--14.找出所有子集的异或总和再求和,15.全排列Ⅱ,16.电话号码的字母组合,17.括号生成
c++·算法·深度优先·回溯
小辉同志7 天前
39. 组合总和
c++·算法·力扣·剪枝·回溯
xiaoye-duck7 天前
《算法题讲解指南:递归,搜索与回溯算法--穷举vs深搜vs回溯vs剪枝》--12.全排列,13.子集
c++·算法·回溯
季明洵20 天前
回溯介绍及实战
java·数据结构·算法·leetcode·回溯
_小草鱼_22 天前
【搜索与图论】DFS算法(深度优先搜索)
算法·深度优先·图论·回溯·递归
We་ct1 个月前
LeetCode 22. 括号生成:DFS回溯解法详解
前端·数据结构·算法·leetcode·typescript·深度优先·回溯
少许极端1 个月前
算法奇妙屋(三十一)-递归、回溯与剪枝的综合问题 4
算法·剪枝·回溯·递归
We་ct1 个月前
LeetCode 79. 单词搜索:DFS回溯解法详解
前端·算法·leetcode·typescript·深度优先·个人开发·回溯