代码随想录-训练营-day20

今天我们继续回溯:

39. 组合总和 - 力扣(LeetCode)

这个题和我们之前的组合题相比,最大的区别在于我们可以无限次的重复取用某值了,这就让我们的递归参数与之前不同,除此之外,本质上这个题与216. 组合总和 III - 力扣(LeetCode)区别并不大,我们依然是用回溯三步法来做:

第一步,确定终止条件,这里这个题除了基本的总和等于target以外,还需要考虑总和大于target,为什么之前不用考虑这个问题呢?因为之前我们不能重复取某值,所以我们只用考虑当总和等于target时将小容器的值返回大容器即可,因为哪怕我们的总和大于了target,只要不是等于target我们都会选择将小容器内元素进行更新。可是这个题因为可以无限次地重复取值,那么如果不加一个总和大于target的判断的话我们没有办法从无限次的重复取值中脱离造成超时。

第二步,我们需要进行遍历并处理节点,我们依然是维护一个总和并将节点放入小容器即可,不过 不同点在于我们不需要在递归时将序号更换为i+1而是i,因为我们现在可以无限次地重复取值,何时不再重复取值呢?当我们的总和大于target时。是的,这一步考虑总和大于target同时满足了我们两步的需求。

第三步,实现回溯,一样的总和减去当前元素且小容器删除当前元素。

代码如下:
 

class Solution {
public:vector<vector<int>> res;vector<int> temp;void backtrack(vector<int>& candidates, int target,int sum,int start){if(sum>target)return;if(sum==target){res.push_back(temp);return;}for(int i=start;i<candidates.size();++i){sum+=candidates[i];temp.push_back(candidates[i]);backtrack(candidates, target, sum, i);sum-=candidates[i];temp.pop_back();}   }vector<vector<int>> combinationSum(vector<int>& candidates, int target) {backtrack(candidates, target, 0, 0);return res;}
};

在这个题中还涉及到了我们的startIndex的讨论,也就是什么时候我们需要去维护一个序号什么时候不用。

如何理解呢?其实很简单:序号是用来控制循环的开始位置的,什么时候我们需要去控制循环的开始位置呢?当我们要求在一个集合内求组合时,我们需要控制每个函数中循环的开始位置以避免重复,这个时候就需要去维护一个startIndex,可是在多个互相不影响的集合中,比如电话号码题,我们只需要在每个集合中取一个字符即可,那么我们就不需要这个序号。

40. 组合总和 II - 力扣(LeetCode)

这个组合题就是上一个组合题的对比版:这个题大集合中的每一个元素都只能取一次,但是对我们输出的结果有去重的要求。

那我们依然还是回溯:

第一步,确定终止条件,那么依然是我们的总和等于target,由于这个题没有无限次地重复取值,我们不用考虑sum大于target的情况。

第二步,遍历,由于是单集合且每个值只能取一次,我们需要一个startIndex来控制循环开始的位置。这里需要留意的有两点:第一是我们这个题希望输出是去重处理的,那具体的去重我们可以在最后进行也可以在遍历时就进行,一般来说我们肯定是希望在遍历时就解决最好。具体如何去重呢?最常见的方法就是我们将大集合排序后再判断当前遍历的值是否与上一个值相同,相同的话就跳过该次循环即可;第二是这个题的一些样例会出现超时的情况,要求我们去进行一些剪枝:什么是剪枝,就是我们可以减少一些不必要的运算。比如这个题中当我们发现目前的值已经大于target了就没必要继续这根子树的遍历了,所以我们在这里也需要添加这个步骤。

最后的回溯没有什么特殊之处,依然是去掉当前的值。

代码如下:

class Solution {
public:vector<vector<int>> res;vector<int> temp;void backtrack(int sum,int target,vector<int>& candidates,int startIndex){if(sum==target){res.push_back(temp);return;}for(int i=startIndex;i<candidates.size();++i){if(i>startIndex&&candidates[i]==candidates[i-1])continue;if(sum+candidates[i]>target)break;sum+=candidates[i];temp.push_back(candidates[i]);backtrack(sum, target, candidates, i+1);sum-=candidates[i];temp.pop_back();}}vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {sort(candidates.begin(), candidates.end());backtrack(0, target, candidates, 0);return res;}
};

至此我们的组合问题就完成了,这五个题中,77. 组合 - 力扣(LeetCode)是最基础的组合问题,也是基本的思路体现。216. 组合总和 III - 力扣(LeetCode)在此基础上加入了对总和的要求,但是从代码和思想上都只是略加修改即可。17. 电话号码的字母组合 - 力扣(LeetCode)就要复杂一些,它不仅要求我们自己去创建哈希表建立数字与字符串的映射,还要求每个数字只能取一个字符,我们需要将这个层级关系整理得足够清晰才可以:我们先取数字,得到这个数字对应的字符串,这个字符串才是我们应该去回溯去遍历的对象,然后我们在for循环外面维护一个数字的字符串的序号去更新数字。39. 组合总和 - 力扣(LeetCode)则是允许无限重复取值,那么我们就需要多考虑sum大于target的情况不然会陷入无限循环,以及递归时不用去更新序号。40. 组合总和 II - 力扣(LeetCode)则是不允许无限取值但要求去重,这就要求我们对大集合进行排序并判断当前遍历元素是否与之前元素相同。

131. 分割回文串 - 力扣(LeetCode)

现在我们来到了分割问题,虽然叫法不一样,但是分割问题与组合问题其实差别没有那么大。

我们都知道组合问题是在一个大集合里找到符合要求的小集合,在遍历的过程中需要做的事就是去读取各个元素,而分割问题实际上也是类似的:我们依然需要维护一个序号,序号前的就是已经被截取的,而序号后的就是我们还没有截取的。

我们用两张图来体现差异:

这是组合问题。

而这就是分割问题,我们依然是用递归实现纵向遍历用for实现横向遍历,将问题抽象成树的遍历问题。

回到题目本身,我们需要不断地去分割字符串并将所有的回文串记录下来并返回。

首先我们依然是回溯的思想:

第一是终止条件:在分割问题中,我们的startIndex就是分割线,那么我们的终止条件就是当startIndex大于等于我们的大集合的大小时,这说明我们找到了所有的分割方法,可以将小容器放入大容器并返回了。

第二是遍历,在这个题中,我们需要去判断子串是否为回文串,首先我们需要一个辅助函数,最简单的就是通过左右指针来判断。然后当我们发现子串为回文串时,我们将子串放入小容器中,否则我们直接continue以跳过这根子树,我们就这样不断地更新分割位置即可(横向遍历)。

第三步是回溯,我们只需要在执行了小容器的push_back操作的基础上进行pop_back即可。

代码如下:

class Solution {
public:vector<vector<string>> res;vector<string> temp;void backtrack(string s,int startIndex){if(startIndex>=s.size()){res.push_back(temp);return;}for(int i=startIndex;i<s.size();++i){if(helper(s, startIndex, i)){string str=s.substr(startIndex,i-startIndex+1);temp.push_back(str);backtrack(s, i+1);temp.pop_back();}else continue;}}bool helper(const string& str,int start,int end){int l=start,r=end;while(l<r){if(str[l]!=str[r])return false;++l;--r;}return true;}vector<vector<string>> partition(string s) {backtrack(s, 0);return res;}
};

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

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

相关文章

ubuntu 本地部署deepseek r1 蒸馏模型

本文中的文件路径或网络代理需要根据自身环境自行删改 一、交互式chat页面 1.1 open-webui 交互窗口部署&#xff1a;基于docker安装&#xff0c;且支持联网搜索 Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 AI 平台&#xff0c;旨在完全离线操作。它支持各种 LLM…

数据库 绪论

目录 数据库基本概念 一.基本概念 1.信息 2.数据 3.数据库&#xff08;DB&#xff09; 4.数据库管理系统&#xff08;DBMS&#xff09; 5.数据库系统&#xff08;DBS&#xff09; 二.数据管理技术的发展 1.人工管理阶段 2.文件系统阶段 3.数据库系统阶段 4.数据库管…

数据中台是什么?:架构演进、业务整合、方向演进

文章目录 1. 引言2. 数据中台的概念与沿革2.1 概念定义2.2 历史沿革 3. 数据中台的架构组成与关键技术要素解析3.1 架构组成3.2 关键技术要素 4. 数据中台与其他平台的对比详细解析 5. 综合案例&#xff1a;金融行业数据中台落地实践5.1 背景5.2 解决方案5.3 成果与价值 6. 方向…

【DeepSeek】DeepSeek概述 | 本地部署deepseek

目录 1 -> 概述 1.1 -> 技术特点 1.2 -> 模型发布 1.3 -> 应用领域 1.4 -> 优势与影响 2 -> 本地部署 2.1 -> 安装ollama 2.2 -> 部署deepseek-r1模型 1 -> 概述 DeepSeek是由中国的深度求索公司开发的一系列人工智能模型&#xff0c;以其…

如何使用C++将处理后的信号保存为PNG和TIFF格式

在信号处理领域&#xff0c;我们常常需要将处理结果以图像的形式保存下来&#xff0c;方便后续分析和展示。C提供了多种库来处理图像数据&#xff0c;本文将介绍如何使用stb_image_write库保存为PNG格式图像以及使用OpenCV库保存为TIFF格式图像。 1. PNG格式保存 使用stb_ima…

查出 product 表中所有 detail 字段包含 xxx 的完整记录

您可以使用以下 SQL 查询语句来查出 product 表中所有 detail 字段包含 oss.kxlist.com 的完整记录&#xff1a; SELECT * FROM product WHERE INSTR(detail, oss.kxlist.com) > 0;下面是detail字段包含的完整内容 <p><img style"max-width:100%;" src…

微服务 day01 注册与发现 Nacos OpenFeign

目录 1.认识微服务&#xff1a; 单体架构&#xff1a; 微服务架构&#xff1a; 2.服务注册和发现 1.注册中心&#xff1a; 2.服务注册&#xff1a; 3.服务发现&#xff1a; 发现并调用服务&#xff1a; 方法1&#xff1a; 方法2&#xff1a; 方法3:OpenFeign OpenFeig…

Shell原理简介与Linux中的权限问题

一、Shell命令及运行原理 1.1通常说的计算机体系结构指的是什么 通常意义上的计算机体系结构指的是芯片&#xff1a; 如锐龙amd&#xff0c;英特尔酷睿intel core 他们分为 x86&#xff1a;32位 x86_64&#xff1a;64位 两种 1.2广义上的Linux系统分为哪些部分&#xf…

在rtthread中,scons构建时,它是怎么知道是从rtconfig.h找宏定义,而不是从其他头文件找?

在rtthread源码中&#xff0c;每一个bsp芯片板级目录下都有一个 SConstruct scons构建脚本的入口&#xff0c; 在这里把rtthread tools/目录下的所有模块都添加到了系统路径中&#xff1a; 在tools下所有模块中&#xff0c;最重要的是building.py模块&#xff0c;在此脚本里面…

C# Winform 使用委托实现C++中回调函数的功能

C# Winform 使用委托实现C中回调函数的功能 在项目中遇到了使用C#调用C封装的接口&#xff0c;其中C接口有一个回调函数的参数。参考对比后&#xff0c;在C#中是使用委托(delegate)来实现类似的功能。 下面使用一个示例来介绍具体的使用方式&#xff1a; 第一步&#xff1a;…

深度学习之神经网络框架搭建及模型优化

神经网络框架搭建及模型优化 目录 神经网络框架搭建及模型优化1 数据及配置1.1 配置1.2 数据1.3 函数导入1.4 数据函数1.5 数据打包 2 神经网络框架搭建2.1 框架确认2.2 函数搭建2.3 框架上传 3 模型优化3.1 函数理解3.2 训练模型和测试模型代码 4 最终代码测试4.1 SGD优化算法…

2025.2.9 每日学习记录2:技术报告写了一半+一点点读后感

0.近期主任务线 1.完成小论文准备 目标是3月份完成实验点1的全部实验和论文。 2.准备教资笔试 打算留个十多天左右&#xff0c;一次性备考笔试的三个科目 1.实习申请技术准备&#xff1a;微调、Agent、RAG 1.今日完成任务 1.电子斗蛐蛐&#xff08;文本书写领域&am…

9 Pydantic复杂数据结构的处理

在构建现代 Web 应用时&#xff0c;我们往往需要处理复杂的输入和输出数据结构。例如&#xff0c;响应数据可能包含嵌套字典、列表、元组&#xff0c;甚至是多个嵌套对象。Pydantic 是一个强大的数据验证和序列化库&#xff0c;可以帮助我们轻松地处理这些复杂的数据结构&#…

链表(LinkedList) 1

上期内容我们讲述了顺序表&#xff0c;知道了顺序表的底层是一段连续的空间进行存储(数组)&#xff0c;在插入元素或者删除元素需要将顺序表中的元素整体移动&#xff0c;时间复杂度是O(n)&#xff0c;效率比较低。因此&#xff0c;在Java的集合结构中又引入了链表来解决这一问…

torch_bmm验算及代码测试

文章目录 1. torch_bmm2. pytorch源码 1. torch_bmm torch.bmm的作用是基于batch_size的矩阵乘法,torch.bmm的作用是对应batch位置的矩阵相乘&#xff0c;比如&#xff0c; mat1的第1个位置和mat2的第1个位置进行矩阵相乘得到mat3的第1个位置mat1的第2个位置和mat2的第2个位置…

shell+kafka实现服务器健康数据搜集

今天有一个徒弟问我&#xff0c;分发、代理服务器都装有kafka&#xff0c;如何快速收集服务器的健康数据&#xff0c;每10秒就收集一次&#xff1f; 我当时听完之后&#xff0c;楞了一下&#xff0c;然后说出了我的见解&#xff1a;认为最快速的方法无法就是建议shell脚本直接采…

macbook2015升级最新MacOS 白苹果变黑苹果

原帖&#xff1a;https://www.bilibili.com/video/BV13V411c7xz/MAC OS系统发布了最新的Sonoma&#xff0c;超酷的动效锁屏壁纸&#xff0c;多样性的桌面小组件&#xff0c;但是也阉割了很多老款机型的升级权利&#xff0c;所以我们可以逆向操作&#xff0c;依旧把老款MAC设备强…

建筑物损坏程度分割数据集labelme格式2816张5类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;2816 标注数量(json文件个数)&#xff1a;2816 标注类别数&#xff1a;5 标注类别名称:["minor-damage","destroyed&quo…

ReactNative进阶(五十九):存量 react-native 项目适配 HarmonyOS NEXT

文章目录 一、前言二、ohos_react_native2.1 Fabric2.2 TurboModule2.2.1 ArkTSTurboModule2.2.2 cxxTurboModule&#xff1a; 三、拓展阅读 一、前言 2024年10月22日19:00&#xff0c;华为在深圳举办“原生鸿蒙之夜暨华为全场景新品发布会”&#xff0c;主题为“星河璀璨&…

Golang GORM系列:GORM CRUM操作实战

在数据库管理中&#xff0c;CRUD操作是应用程序的主干&#xff0c;支持数据的创建、检索、更新和删除。强大的Go对象关系映射库GORM通过抽象SQL语句的复杂性&#xff0c;使这些操作变得轻而易举。本文是掌握使用GORM进行CRUD操作的全面指南&#xff0c;提供了在Go应用程序中有效…