代码随想录算法训练营第二十四天 | 回溯算法 77.组合

回溯算法理论基础

文章讲解 视频讲解

  • 回溯是递归的副产品,只要有回溯就会有递归
  • 回溯的本质是琼剧,所以效率不高

回溯法可以解决的问题

  • 组合问题
  • 切割问题
  • 子集问题
  • 排列问题
  • 棋盘问题

如何理解回溯

  • 回溯算法的问题都可以抽象为树形结构
  • 集合的大小就构成了书的快读,递归的深度就构成了树的深度

回溯法模板

回溯三部曲

  • 回溯函数返回值及参数
    返回值一般为void,参数通常不固定,先写逻辑需要什么参数再传什么参数

    void backtracking(参数)
    
  • 回溯函数终止条件
    一般来说搜索到叶子节点就可以回溯了

    if(终止条件) {
      存放结果;
      return;
    }
    
  • 回溯搜索的遍历过程

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

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

77.组合

题目链接 文章讲解 视频讲解

class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        vector<int> path;
        vector<vector<int>> ans;
        backtracking(n, k, path, ans, 1);
        return ans;
    }

    void backtracking(int n, int k, vector<int>& path, vector<vector<int>>& ans, int startIndex) {
        // 终止条件
        if(path.size() == k) {
            ans.push_back(path);
            return ;
        }
        
        for(int i = startIndex; i <= n; ++i) {
            // 处理节点
            path.push_back(i);
            // 递归
            
            backtracking(n, k, path, ans, i + 1);
            
            // 回溯
            path.pop_back();

        }
    }
};

剪枝优化

思路:当集合中剩余的元素不够还需要的元素个数时,应该终止遍历
还需要:k - path.size()
剩余:n - i + 1;
n - i + 1 >= k -path.size() --> i <= n - k + path.size() + 1;

class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        vector<int> path;
        vector<vector<int>> ans;
        backtracking(n, k, path, ans, 1);
        return ans;
    }

    void backtracking(int n, int k, vector<int>& path, vector<vector<int>>& ans, int startIndex) {
        // 终止条件
        if(path.size() == k) {
            ans.push_back(path);
            return ;
        }
        // 修改循环终止条件进行剪枝
        for(int i = startIndex; i <= n - k + path.size() + 1; ++i) {
            // 处理节点
            path.push_back(i);
            // 递归
            
            backtracking(n, k, path, ans, i + 1);
            
            // 回溯
            path.pop_back();

        }
    }
};
posted @ 2024-06-04 12:31  深蓝von  阅读(2)  评论(0编辑  收藏  举报