当前位置: 首页 > news >正文

leetcode刷题-代码训练营-第7章-回溯算法1

回溯法模板

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

理解

 从图中看出for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了

回溯法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯就容易多了

第77题. 组合

 理解

回溯代码

class Solution {
private:vector<vector<int>> result; // 存放符合条件结果的集合vector<int> path; // 用来存放符合条件结果void backtracking(int n, int k, int startIndex) {if (path.size() == k) {result.push_back(path);return;}for (int i = startIndex; i <= n; i++) {path.push_back(i); // 处理节点 backtracking(n, k, i + 1); // 递归path.pop_back(); // 回溯,撤销处理的节点}}
public:vector<vector<int>> combine(int n, int k) {result.clear(); // 可以不写path.clear();   // 可以不写backtracking(n, k, 1);return result;}
};

剪枝操作

class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(int n, int k, int startIndex) {if (path.size() == k) {result.push_back(path);return;}for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) { // 优化的地方path.push_back(i); // 处理节点backtracking(n, k, i + 1);path.pop_back(); // 回溯,撤销处理的节点}}
public:vector<vector<int>> combine(int n, int k) {backtracking(n, k, 1);return result;}
};

216.组合总和III

思路

回溯算法

class Solution {
private:vector<vector<int>> result; // 存放结果集vector<int> path; // 符合条件的结果// targetSum:目标和,也就是题目中的n。// k:题目中要求k个数的集合。// sum:已经收集的元素的总和,也就是path里元素的总和。// startIndex:下一层for循环搜索的起始位置。void backtracking(int targetSum, int k, int sum, int startIndex) {if (path.size() == k) {if (sum == targetSum) result.push_back(path);return; // 如果path.size() == k 但sum != targetSum 直接返回}for (int i = startIndex; i <= 9; i++) {sum += i; // 处理path.push_back(i); // 处理backtracking(targetSum, k, sum, i + 1); // 注意i+1调整startIndexsum -= i; // 回溯path.pop_back(); // 回溯}}public:vector<vector<int>> combinationSum3(int k, int n) {result.clear(); // 可以不加path.clear();   // 可以不加backtracking(n, k, 0, 1);return result;}
};

剪枝操作

class Solution {
private:vector<vector<int>> result; // 存放结果集vector<int> path; // 符合条件的结果void backtracking(int targetSum, int k, int sum, int startIndex) {if (sum > targetSum) { // 剪枝操作return; // 如果path.size() == k 但sum != targetSum 直接返回}if (path.size() == k) {if (sum == targetSum) result.push_back(path);return;}for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) { // 剪枝sum += i; // 处理path.push_back(i); // 处理backtracking(targetSum, k, sum, i + 1); // 注意i+1调整startIndexsum -= i; // 回溯path.pop_back(); // 回溯}}public:vector<vector<int>> combinationSum3(int k, int n) {result.clear(); // 可以不加path.clear();   // 可以不加backtracking(n, k, 0, 1);return result;}
};

17.电话号码的字母组合

 39. 组合总和

思路

回溯法代码

// 版本一
class Solution {
private:const string letterMap[10] = {"", // 0"", // 1"abc", // 2"def", // 3"ghi", // 4"jkl", // 5"mno", // 6"pqrs", // 7"tuv", // 8"wxyz", // 9};
public:vector<string> result;string s;void backtracking(const string& digits, int index) {if (index == digits.size()) {result.push_back(s);return;}int digit = digits[index] - '0';        // 将index指向的数字转为intstring letters = letterMap[digit];      // 取数字对应的字符集for (int i = 0; i < letters.size(); i++) {s.push_back(letters[i]);            // 处理backtracking(digits, index + 1);    // 递归,注意index+1,一下层要处理下一个数字了s.pop_back();                       // 回溯}}vector<string> letterCombinations(string digits) {s.clear();result.clear();if (digits.size() == 0) {return result;}backtracking(digits, 0);return result;}
};

思路

回溯算法

// 版本一
class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {if (sum > target) {return;}if (sum == target) {result.push_back(path);return;}for (int i = startIndex; i < candidates.size(); i++) {sum += candidates[i];path.push_back(candidates[i]);backtracking(candidates, target, sum, i); // 不用i+1了,表示可以重复读取当前的数sum -= candidates[i];path.pop_back();}}
public:vector<vector<int>> combinationSum(vector<int>& candidates, int target) {result.clear();path.clear();backtracking(candidates, target, 0, 0);return result;}
};

优化代码

 对总集合排序之后,如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历

在求和问题中,排序之后加剪枝是常见的套路!

class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {if (sum == target) {result.push_back(path);return;}// 如果 sum + candidates[i] > target 就终止遍历for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {sum += candidates[i];path.push_back(candidates[i]);backtracking(candidates, target, sum, i);sum -= candidates[i];path.pop_back();}}
public:vector<vector<int>> combinationSum(vector<int>& candidates, int target) {result.clear();path.clear();sort(candidates.begin(), candidates.end()); // 需要排序backtracking(candidates, target, 0, 0);return result;}
};

http://www.lryc.cn/news/335807.html

相关文章:

  • 三种常见webshell工具的流量特征分析
  • pkg打包nodejs程序用动态require路由出现问题
  • 设计模式(018)行为型之策略模式
  • c++关键字: =delete和=default
  • JSON
  • Python | 超前滞后分析
  • Linux CPU利用率
  • vue3实现导出pdf、png功能
  • what is tty?
  • 在vite中限制node版本
  • 07 Php学习:运算符
  • 做了多年前端,有没有想在python,go,nodejs,.net,java,c++中学一门后端,推荐
  • JR-SMD201-P便携式网络解码器
  • 线程池阻塞队列的选择
  • linux内核驱动-在内核代码里添加设备结点
  • 【算法优选】 动态规划之简单多状态dp问题——贰
  • 【算法刷题 | 二叉树 06】4.10( 路径总和、路径总和 || )
  • 代码学习记录37----动态规划
  • Spring Boot:Web开发之三大组件的整合
  • 2024.3.15力扣每日一题——卖木头块
  • vue快速入门(七)内联语句
  • Docker实战教程 第2章 Docker基础
  • 【S32K3 MCAL配置】-3.2-CANFD配置-发送“经典CAN/CANFD标准帧“和“经典CAN/CANFD扩展帧“(基于MCAL+FreeRTOS)
  • 【airtest】自动化入门教程(四)Poco元素定位
  • Go语言中如何处理goroutine和循环变量
  • Pytest教程:一文了解如何使用 pytest_runtest_makereport 修改 Pytest 测试报告内容
  • 《高通量测序技术》分享,生物信息学生信流程的性能验证,以肿瘤NGS基因检测为例。
  • Django+Celery框架自动化定时任务开发
  • 解决element-plus table组件 fixed=“right“(left)浮动后横向滚动文字穿透的问题
  • 【opencv】示例-distrans.cpp 距离变换