回溯算法|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;}
};

回溯算法那个模板你了解了嘛

其实多用几次它就能很好的理解这类题目了

代码随想录 (programmercarl.com)

思路

本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合。

相对于77. 组合 (opens new window),无非就是多了一个限制,本题是要找到和为n的k个数的组合,而整个集合已经是固定的了[1,...,9]。

想到这一点了,做过77. 组合 (opens new window)之后,本题是简单一些了。

本题k相当于树的深度,9(因为整个集合就是9个数)就是树的宽度。

例如 k = 2,n = 4的话,就是在集合[1,2,3,4,5,6,7,8,9]中求 k(个数) = 2, n(和) = 4的组合。

选取过程如图:

216.组合总和III

图中,可以看出,只有最后取到集合(1,3)和为4 符合条件。

#回溯三部曲

  • 确定递归函数参数

和77. 组合 (opens new window)一样,依然需要一维数组path来存放符合条件的结果,二维数组result来存放结果集。

这里我依然定义path 和 result为全局变量。

至于为什么取名为path?从上面树形结构中,可以看出,结果其实就是一条根节点到叶子节点的路径。

vector<vector<int>> result; // 存放结果集
vector<int> path; // 符合条件的结果

接下来还需要如下参数:

  • targetSum(int)目标和,也就是题目中的n。
  • k(int)就是题目中要求k个数的集合。
  • sum(int)为已经收集的元素的总和,也就是path里元素的总和。
  • startIndex(int)为下一层for循环搜索的起始位置。

所以代码如下:

vector<vector<int>> result;
vector<int> path;
void backtracking(int targetSum, int k, int sum, int startIndex)

其实这里sum这个参数也可以省略,每次targetSum减去选取的元素数值,然后判断如果targetSum为0了,说明收集到符合条件的结果了,我这里为了直观便于理解,还是加一个sum参数。

还要强调一下,回溯法中递归函数参数很难一次性确定下来,一般先写逻辑,需要啥参数了,填什么参数。

  • 确定终止条件

什么时候终止呢?

在上面已经说了,k其实就已经限制树的深度,因为就取k个元素,树再往下深了没有意义。

所以如果path.size() 和 k相等了,就终止。

如果此时path里收集到的元素和(sum) 和targetSum(就是题目描述的n)相同了,就用result收集当前的结果。

所以 终止代码如下:

if (path.size() == k) {if (sum == targetSum) result.push_back(path);return; // 如果path.size() == k 但sum != targetSum 直接返回
}

  • 单层搜索过程

本题和77. 组合 (opens new window)区别之一就是集合固定的就是9个数[1,...,9],所以for循环固定i<=9

如图: 

216.组合总和III

处理过程就是 path收集每次选取的元素,相当于树型结构里的边,sum来统计path里元素的总和。

代码如下:

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(); // 回溯
}

别忘了处理过程 和 回溯过程是一一对应的,处理有加,回溯就要有减!

参照关于回溯算法,你该了解这些! (opens new window)中的模板,不难写出如下C++代码:

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;}
};

#剪枝

这道题目,剪枝操作其实是很容易想到了,想必大家看上面的树形图的时候已经想到了。

如图: 

216.组合总和III1

已选元素总和如果已经大于n(图中数值为4)了,那么往后遍历就没有意义了,直接剪掉。

那么剪枝的地方可以放在递归函数开始的地方,剪枝代码如下:

if (sum > targetSum) { // 剪枝操作return;
}

当然这个剪枝也可以放在 调用递归之前,即放在这里,只不过要记得 要回溯操作给做了。

for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) { // 剪枝sum += i; // 处理path.push_back(i); // 处理if (sum > targetSum) { // 剪枝操作sum -= i; // 剪枝之前先把回溯做了path.pop_back(); // 剪枝之前先把回溯做了return;}backtracking(targetSum, k, sum, i + 1); // 注意i+1调整startIndexsum -= i; // 回溯path.pop_back(); // 回溯
}

和回溯算法:组合问题再剪剪枝 (opens new window)一样,for循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1就可以了。

最后C++代码如下:

class Solution {
private:vector<vector<int>> result; // 存放结果集vector<int> path; // 符合条件的结果void backtracking(int targetSum, int k, int sum, int startIndex) {if (sum > targetSum) { // 剪枝操作return; }if (path.size() == k) {if (sum == targetSum) result.push_back(path);return; // 如果path.size() == k 但sum != targetSum 直接返回}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;}
};

  • 时间复杂度: O(n * 2^n)
  • 空间复杂度: O(n)

自己的理解:

关于枝剪这一步的优化,自己还不是很明白。

然后还有注意命名,好的命名可以让你在敲代码时事半功倍~

以下是自己独自敲的代码,还是会有点小问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/782374.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenKylin安装Kafka

一、操作系统 openKylin 1.0.1 X86 二、下载安装包 # 安装依赖jdk sudo apt-get update sudo apt-get install default-jdk # 下载kafka mkdir -p /data/software/kafka wget https://archive.apache.org/dist/kafka/2.4.1/kafka_2.13-2.4.1.tgz三、解压安装 # 解压缩Kafka…

springboot项目学习-瑞吉外卖(4)续

1.任务 菜品的添加功能(涉及到两张表的数据添加) 2.菜品添加 功能页面如上&#xff0c;该页面有两个注意点 菜品分类&#xff1a;点击菜品分类后&#xff0c;会展示当前已有菜品&#xff1a;这个功能的实现要从category表里查询数据&#xff0c;然后再做展示口味做法配置&#…

算法题->移动零的C语言和JAVA的双指针解法

使用C语言和JAVA代码通过双指针进行解题 题目描述:给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 理解题意:不改变数组中非零元素的顺序,并把0元素放在非零元素后面. 链接: https://leetcode.cn/problems/m…

Linux——将云服务器作为跳板机,frp实现内网穿透

文章目录 操作步骤1. 准备工作&#xff1a;2. 配置frp服务器端&#xff1a;3. 配置frp客户端&#xff1a;4. 启动frp客户端&#xff1a;5. 测试连接&#xff1a;6. 安全注意事项&#xff1a; 云服务器性能分析阿里云具体操作步骤1. 购买&#xff1a;2. 登录&#xff1a;3. 首次…

【springboot】闲话 springboot 的几种异步机制 及 长轮询的概念和简单实现

文章目录 引子springboot的几种异步形式开启异步支持和线程池配置&#xff08;重要&#xff09;第一种&#xff1a;Async第二种&#xff1a;Callable<T>第三种&#xff1a;WebAsyncTask<T>第四种&#xff1a;DeferredResult<T> 长轮询的简单实现概念实现服务…

spring boot-引入Redis并封装redistemplate操作工具类

文章目录 一、关于spring-redis二、springboot引入Redis及其使用案例三、封装redistemplate操作工具类 一、关于spring-redis spring-data-redis针对jedis提供了如下功能&#xff1a; 连接池自动管理&#xff0c;提供了一个高度封装的“RedisTemplate”类 针对jedis客户端中大…

设置 Linux 时间同步 同步硬件时钟

设置 Linux 时间同步 同步硬件时钟 配置 NTP 客户端查看当前系统时间使用 ntpdate 命令手动同步时间同步硬件时钟再次检查硬件时钟参考 配置 NTP 客户端 vim /etc/systemd/timesyncd.conf[Time] NTPcn.pool.ntp.org FallbackNTPasia.pool.ntp.org ntp.aliyun.com ntp1.aliyun.…

acwing算法提高之图论--单源最短路的扩展应用

目录 1 介绍2 训练 1 介绍 本专题用来记录使用。。。。 2 训练 题目1&#xff1a;1137选择最佳线路 C代码如下&#xff0c; #include <iostream> #include <cstring> #include <algorithm> #include <queue>using namespace std;const int N 101…

编译amd 的 amdgpu 编译器

1,下载源码 git clone --recursive https://github.com/ROCm/llvm-project.git 2, 配置cmake cmake -G "Unix Makefiles" ../llvm \ -DLLVM_ENABLE_PROJECTS"clang;clang-tools-extra;compiler-rt" \ -DLLVM_BUILD_EXAMPLESON …

springboot企业级抽奖项目业务四 (缓存预热)

缓存预热 为什么要做预热: 当活动真正开始时&#xff0c;需要超高的并发访问活动相关信息 必须把必要的数据提前加载进redis 预热的策略: 在msg中写一个定时任务 每分钟扫描一遍card_game表 把(开始时间 > 当前时间)&& (开始时间 < 当前时间1分钟)的活动及相…

CrossOver软件2024免费 最新版本详细介绍 CrossOver软件好用吗 Mac电脑玩Windows游戏

CrossOver是一款由CodeWeavers公司开发的软件&#xff0c;它可以在Mac和Linux等操作系统上运行Windows软件&#xff0c;而无需在计算机上安装Windows操作系统。这款软件的核心技术是Wine&#xff0c;它是一种在Linux和macOS等操作系统上运行Windows应用程序的开源软件。 Cross…

大语言模型---强化学习

本文章参考&#xff0c;原文链接&#xff1a;https://blog.csdn.net/qq_35812205/article/details/133563158 SFT使用交叉熵损失函数&#xff0c;目标是调整参数使模型输出与标准答案一致&#xff0c;不能从整体把控output质量 RLHF&#xff08;分为奖励模型训练、近端策略优化…

HarmonyOS 应用开发之FA模型绑定Stage模型ServiceExtensionAbility

本文介绍FA模型的三种应用组件如何绑定Stage模型的ServiceExtensionAbility组件。 PageAbility关联访问ServiceExtensionAbility PageAbility关联访问ServiceExtensionAbility和PageAbility关联访问ServiceAbility的方式完全相同。 import featureAbility from ohos.ability…

Adaboost集成学习 | Matlab实现基于ELM-Adaboost极限学习机结合Adaboost集成学习时间序列预测(股票价格预测)

目录 效果一览基本介绍模型设计程序设计参考资料效果一览 基本介绍 基于ELM-Adaboost极限学习机结合Adaboost集成学习时间序列预测(股票价格预测) 单变量时间序列单步预测。 ELM(Extreme Learning Machine,极限学习机)和AdaBoost(Adaptive Boosting,自适应提升)都是机…

c++----list模拟实现

目录 1. list的基本介绍 2. list的基本使用 2.1 list的构造 用法示例 2.2 list迭代器 用法示例 2.3. list容量&#xff08;capacity&#xff09;与访问&#xff08;access) 用法示例 2.4 list modifiers 用法示例 2.5 list的迭代器失效 3.list的模拟实现 3.1…

使用Python实现ID3决策树中特征选择的先后顺序,字节跳动面试真题

def empty1(pri_data): hair [] #[‘长’, ‘短’, ‘短’, ‘长’, ‘短’, ‘短’, ‘长’, ‘长’] voice [] #[‘粗’, ‘粗’, ‘粗’, ‘细’, ‘细’, ‘粗’, ‘粗’, ‘粗’] sex [] #[‘男’, ‘男’, ‘男’, ‘女’, ‘女’, ‘女’, ‘女’, ‘女’] for o…

leetcode.209.长度最小的子数组

题目 给定一个含有 n 个正整数的数组和一个正整数 s &#xff0c;找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组&#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0。 示例&#xff1a; 输入&#xff1a;s 7, nums [2,3,1,2,4,3] 输出&#…

sqli第24关二次注入

注入点 # Validating the user input........$username $_SESSION["username"];$curr_pass mysql_real_escape_string($_POST[current_password]);$pass mysql_real_escape_string($_POST[password]);$re_pass mysql_real_escape_string($_POST[re_password]);if($p…

wps斜线表头并分别打字教程

wps斜线表头怎么做并分别打字&#xff1a; 1、首先选中我们想要设置的表头。 2、接着右键选中它&#xff0c;点击“设置单元格格式” 3、然后点击上方“边框”选项卡。 4、随后选择图示的斜线&#xff0c;点击“确定” 5、设置完成后&#xff0c;我们只要在其中打字就可以在斜…

算法学习——LeetCode力扣图论篇2

算法学习——LeetCode力扣图论篇2 1020. 飞地的数量 1020. 飞地的数量 - 力扣&#xff08;LeetCode&#xff09; 描述 给你一个大小为 m x n 的二进制矩阵 grid &#xff0c;其中 0 表示一个海洋单元格、1 表示一个陆地单元格。 一次 移动 是指从一个陆地单元格走到另一个相…