代码随想录训练营Day 29|力扣39. 组合总和、40.组合总和II、131.分割回文串

1.组合总和

题目链接/文章讲解: 代码随想录

视频讲解:带你学透回溯算法-组合总和(对应「leetcode」力扣题目:39.组合总和)| 回溯法精讲!_哔哩哔哩_bilibili

代码:(未剪枝版 )

class Solution {
private:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& candidates,int target,int startIndex){// 递归出口if(target < 0){return;}if(target == 0){result.push_back(path);return;}// 处理结点for(int i = startIndex;i < candidates.size();i++){target -= candidates[i];path.push_back(candidates[i]);backtracking(candidates,target,i);path.pop_back();target += candidates[i];}}
public:vector<vector<int>> combinationSum(vector<int>& candidates, int target) {if(candidates.size() == 0) return result;backtracking(candidates,target,0);return result;}
};

 代码:(剪枝版)

class Solution {
private:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& candidates,int target,int startIndex){// 递归出口if(target < 0){return;}if(target == 0){result.push_back(path);return;}// 处理结点// 这里加了判断:如果下一轮的target已经小于0了,就没有必要递归了for(int i = startIndex;i < candidates.size() && target - candidates[i] >= 0;i++){target -= candidates[i];path.push_back(candidates[i]);backtracking(candidates,target,i);path.pop_back();target += candidates[i];}}
public:vector<vector<int>> combinationSum(vector<int>& candidates, int target) {if(candidates.size() == 0) return result;sort(candidates.begin(), candidates.end()); // 涉及大小的剪枝必排序backtracking(candidates,target,0);return result;}
};

思路:学到了这种元素数量不限制的取的解法

其实startIndex变量还是要有,因为我们求的是组合,要数层去重;并且这是在同一个数组里取数。

而数量不限,体现在我在递归里传入的starIndex的值是i,而不是i+1了。之前说过for循环管控每一层数的宽度;递归则管控数的深度。这样更改后,就可以在取完一个数的情况后,继续取这个数。实现如下图所示的效果:

关于剪枝的操作。这种涉及到总和大小的取值时。剪枝就要将给定的数组排序! 而且要注意给定的数组元素里全是正数,只有正数才越加越大。

这道题,我直接用目标总和target取减去每一个结点的数值了,看最后是否被减为0了。

2.组合总和2 

 题目链接/文章讲解:代码随想录

视频讲解:回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II_哔哩哔哩_bilibili

 代码:去重且剪枝过的

class Solution {
private:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& candidates,int target,int startIndex,vector<bool>& used){if(target < 0){return;}if(target == 0){result.push_back(path);return;}for(int i = startIndex;i < candidates.size() && target - candidates[i] >= 0;i++){// used[i - 1] == true,说明同一树枝candidates[i - 1]使用过// used[i - 1] == false,说明同一树层candidates[i - 1]使用过// 要对同一树层使用过的元素进行跳过if(i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false){continue;} // 数层去重used[i] = true;target -= candidates[i];path.push_back(candidates[i]);backtracking(candidates,target,i + 1,used);path.pop_back();target += candidates[i];used[i] = false;}}
public:vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {vector<bool> used(candidates.size(),false);sort(candidates.begin(),candidates.end());backtracking(candidates,target,0,used);return result;}
};

思路:

这道题和上题的区别是:

每个元素只能使用一次——startIndex为i+1;

给定的元素有重复值,但是要去重后的结果:这里就是难点。首先去重是有两个维度的。

 一个组合里可以有相同大小的不同元素,所以递归操作里不需要去重,即上图的同一个子树的数枝上不需要去重;不同组合不能相同,所以要在数层去重。

这里用一个数组used来记录,遇到的和前一个元素相同的情况(这里去重先去把给定数组排序)时,到底是和前一个相同元素是在同一个树枝里的,还是同一个树层里的。

在同一个树枝里:前一个元素已经加入到了path里,已经使用过了。

在同一个树层里:前一个元素没有加入到path里,没有被使用,这是独立的两个分支。

所以如果遇到这种树层里重复的情况,加个判断语句,直接continue(因为接下来的情况还有我们要收集的,所以只是跳过这一种情况,用continue)

3.分割回文串

代码随想录

视频讲解:带你学透回溯算法-分割回文串(对应力扣题目:131.分割回文串)| 回溯法精讲!_哔哩哔哩_bilibili

 代码:

class Solution {
private:vector<string> path;vector<vector<string>> result;bool isPalindrome(string& s,int start,int end){while(start <= end){if(s[start] != s[end]){return false;}start++;end--;}return true;}void backtracking(string& s,int startIndex){// 递归出口if(startIndex >= s.size()){result.push_back(path);return;}// 遍历结点// 回文子串的范围是[startIndex,i]for(int i = startIndex;i < s.size();i++){// 在这里直接判断是否子串满足回文子串if(isPalindrome(s,startIndex,i)){string str = s.substr(startIndex,i - startIndex + 1);path.push_back(str);}else{continue;}backtracking(s,i + 1);path.pop_back();}}
public:vector<vector<string>> partition(string s) {if(s.size() == 0) return result;backtracking(s,0);return result;}
};

思路:

关于substr函数:

这道题很巧妙地将startIndex作为了子串的开始下标,子串的范围可以表示为[startIndex,i]。

同时,本题将判断条件放在了for循环的里面来判断,来决定是否要执行下面的递归回溯操作。判断用了一个额外的函数来判断回文子串。 

细节问题其实就这些。

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

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

相关文章

aigc在前端中的应用-CodeGeex

前言&#xff1a;目前市场上优秀的智能编程助手有很多&#xff0c;其中以GitHub Copilot&#xff0c;Tabnine为最&#xff0c;但是目前这两款优质的智能编程助手都是需要付费的。如果不选择花费的话&#xff0c;在这里我们向小伙伴推荐免费的智能编程助手codegeex&#xff0c;性…

C#【进阶】委托和事件

委托和事件 文章目录 1、委托1、委托概念2、基本语法3、定义自定义委托4、使用自定义委托5、委托变量可以存储多个函数6、系统定义好的委托思考 怪物死亡数据更新 2、事件1、事件概念2、事件的使用3、为什么有事件思考 热水器 3、匿名函数1、匿名函数概念2、基本语法3、使用4、…

ASP.NET在线二手交易系统的设计与实现

摘 要 随着当今社会信息技术的进步&#xff0c;基于互联网的各种应用日益受到了人们的重视&#xff0c;二手商品的重新利用也逐渐被人们关注&#xff0c;二手交易系统就在这种形势下产生了&#xff0c;它利用网络&#xff0c;改变了人们的购物方式。 本文是基于现代二手交易…

Kotlin扩展函数和运算符重载

扩展函数 fun String.lettersCount():Int{var count 0for(i in this){if(i.isLetter())count}return count } fun main(){val str:String "12we"println(str.lettersCount()) } 相当于直接将方法写在类里面。函数体内可以直接使用this而不用传参。 运算符重载 …

基于Python的jieba库分析《斗破苍穹》文本中的高频词汇

分析《斗破苍穹》文本中的高频词汇 在进行文本分析时&#xff0c;了解文本中出现频率较高的词汇对于把握文本的主题和风格非常有帮助。本文将介绍如何使用Python的jieba库对《斗破苍穹》这部小说的文本进行分词处理&#xff0c;并统计高频词汇的出现次数&#xff08;本文只统计…

AI作画算法详解:原理、应用与未来发展

随着人工智能技术的不断发展&#xff0c;AI作画逐渐成为了一个热门话题。AI作画&#xff0c;即利用人工智能算法生成绘画作品&#xff0c;不仅仅是技术的展示&#xff0c;更是艺术与科技结合的创新体现。本文将深入探讨AI作画的核心算法原理&#xff0c;并通过实例帮助读者更好…

自然语言处理通用框架BERT原理解读

相关代码见文末 1.概述 问题背景: 传统Seq2Seq模型的局限性: 早期的机器翻译和文本生成任务常采用基于循环神经网络(RNN)的序列到序列(Seq2Seq)模型,这类模型在处理长序列时容易遇到梯度消失/爆炸问题,导致训练效率低,难以捕捉长期依赖。 RNN网络的问题: RNN及其变…

哈希表的理解和实现

目录 1. 哈希的概念 (是什么) 2. 实现哈希的两种方式 (哈希函数) 2.1. 直接定址法 2.2. 除留余数法 2.2.1. 哈希冲突 3. 补充知识 3.1. 负载因子 3.2. 线性探测和二次探测 4. 闭散列实现哈希表 (开放定址法) 4.1. 开放定址法的实现框架 4.2. Xq::hash_table::insert…

mysql 查询---多表设计

部分数据 1distinct去重 select distinct job from tb_emp;select * from tb_emp where id in (1,2,3); select * from tb_emp where id between 1 and 5; select * from tb_emp where name like __; #下划线匹配单个字符, %匹配任意多个字符select min(entrydate) from tb_e…

C++ 日志库 log4cpp 编译、压测及其范例代码 [全流程手工实践]

文章目录 一、 log4cpp官网二、下载三、编译1.目录结构如下2.configure 编译3.cmake 编译 四、测试五、压测源码及结果1.运行环境信息2.压测源码3.压测结果 文章内容&#xff1a;包含了对其linux上的完整使用流程&#xff0c;下载、编译、安装、测试用例尝试、以及一份自己写好…

机器学习入门介绍

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 目录 三大方向机器学习产生的原因机器如何学习…

springboot整合rabbitmq的不同工作模式理解

前提是已经安装并启动了rabbitmq&#xff0c;并且项目已经引入rabbitmq&#xff0c;完成了配置。 不同模式所需参数不同&#xff0c;生产者可以根据参数不同使用重载的convertAndSend方法。而消费者均是直接监听某个队列。 不同的交换机是实现不同工作模式的关键组件.每种交换…