第七章 回溯算法part03

  • 39. 组合总和
  • 40.组合总和II
  • 131.分割回文串

一、组合总和

力扣题目链接 (opens new window)

回溯三部曲

1、回溯函数参数及返回值,用parh放结果,result放结果集,所以不用返回值,而参数则用集合cand和目标值还有总和和开始值

vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int sum, int startIndex)

2、递归终止条件

当总和sum大于目标值的时候返回,当等于目标值的时候送到结果集中。

if (sum > target) {return;
}
if (sum == target) {result.push_back(path);return;
}

3、单层搜索逻辑

这里依然是for循环表示广度,回溯函数表示深度,当for循环取一个值的时候是直接走到底,然后再一步步回溯。

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

整体代码:

class Solution {
public:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& cand,int target,int sum,int startindex){if(sum>target){return;}if(sum==target){result.push_back(path);return;}for(int i=startindex;i<cand.size();i++){sum+=cand[i];path.push_back(cand[i]);backtracking(cand,target,sum,i);sum-=cand[i];path.pop_back();}}vector<vector<int>> combinationSum(vector<int>& candidates, int target) {result.clear();path.clear();backtracking(candidates,target,0,0);return result;}
};

下面还给出了剪枝的方法,就是sum加上这个点的值如果大于目标值,就不用进行循环了,但这里注意需要对集合排序,以免错过后续的结果。

for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {

二、组合总和II

力扣题目链接 (opens new window)

class Solution {
public: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++){if(i!=0&&candidates[i]==candidates[i-1]){continue;}sum+=candidates[i];path.push_back(candidates[i]);backtracking(candidates,target,sum,i+1);sum-=candidates[i];path.pop_back();}}vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {result.clear();path.clear();sort(candidates.begin(),candidates.end());backtracking(candidates,target,0,0);return result;}
};

我自己给写了一段错误代码,这代码的错误在于剪枝减太多了,将组合中有相同元素的情况,比如【1,1,6】的情况减去了。

首先回溯三部曲的前两步其实是差不多的

但是涉及到剪枝,所以在递归函数的定义上,需要去加上一个used集合

这块确实抽象,意思其实就是当取后面的数的时候used[i-1]就是表明回溯的时候是否使用过前面的一个值,如果为true则在path集中是存在前一个数的,反之则不存在。

这里有什么用呢,这个能充分保证,二者共存的集合是可以被使用的,而避免了取前一个或当前数据造成的重复集合。

整体代码:

class Solution {
public:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& candidates,int target,int sum,int startindex,vector<bool> used){if(sum>target){return;}if(sum==target){result.push_back(path);return;}for(int i=startindex;i<candidates.size();i++){if(i!=0&&candidates[i]==candidates[i-1]&&used[i-1]==false){continue;}sum+=candidates[i];path.push_back(candidates[i]);used[i]=true;backtracking(candidates,target,sum,i+1,used);used[i]=false;sum-=candidates[i];path.pop_back();}}vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {vector<bool> used(candidates.size(), false);result.clear();path.clear();sort(candidates.begin(),candidates.end());backtracking(candidates,target,0,0,used);return result;}
};

看了下面的startindex剪枝,发现自己上面的方法就差一点,原因是因为回溯中把两个[1,1,6]都减去了。

3、分割回文串

力扣题目链接 (opens new window)

回溯三部曲:

1、递归函数参数

依然是result,path两个数组存放,因为要回溯,所以把string放入,而且还需要startindex。

vector<vector<string>> result;
vector<string> path; // 放已经回文的子串
void backtracking (const string& s, int startIndex) {

2、递归函数的终止条件

如果遍历到最后则返回

void backtracking (const string& s, int startIndex) {// 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了if (startIndex >= s.size()) {result.push_back(path);return;}
}

3、单层递归逻辑

如果是回文串,则需要切割字符串,将结果放入path同时继续遍历。

for (int i = startIndex; i < s.size(); i++) {if (isPalindrome(s, startIndex, i)) { // 是回文子串// 获取[startIndex,i]在s中的子串string str = s.substr(startIndex, i - startIndex + 1);path.push_back(str);} else {                // 如果不是则直接跳过continue;}backtracking(s, i + 1); // 寻找i+1为起始位置的子串path.pop_back();        // 回溯过程,弹出本次已经填在的子串
}

整体代码:

class Solution {
public:vector<vector<string>> result;vector<string> path;bool ispalind(const string&s,int start,int end){for(int i=start,j=end;i<j;i++,j--){if(s[i]!=s[j]){return false;}}return true;}void backtracking(const string& s,int startindex){if(startindex>=s.size()){result.push_back(path);return;}for(int i=startindex;i<s.size();i++){if(ispalind(s,startindex,i)){string str =s.substr(startindex,i-startindex+1);path.push_back(str);}else{continue;}backtracking(s,i+1);path.pop_back();}}vector<vector<string>> partition(string s) {result.clear();path.clear();backtracking(s,0);return result;}
};

自己照着三部曲写的代码,感觉还不错

此代码还有优化逻辑:由于证明字符串是否是回文字符串存在重复计算,此时如果直接将一个字符串的所有情况一一取出,在进行查询就可以避免重复计算。

而提前计算的逻辑就是二维布尔数组,i从大到小,j从i开始变大,以保证在i行时,i+行计算完毕,同时在同一行中,每一个结果可以根据前一个结果产生。

void computePalindrome(const string& s) {// isPalindrome[i][j] 代表 s[i:j](双边包括)是否是回文字串 isPalindrome.resize(s.size(), vector<bool>(s.size(), false)); // 根据字符串s, 刷新布尔矩阵的大小for (int i = s.size() - 1; i >= 0; i--) { // 需要倒序计算, 保证在i行时, i+1行已经计算好了for (int j = i; j < s.size(); j++) {if (j == i) {isPalindrome[i][j] = true;}else if (j - i == 1) {isPalindrome[i][j] = (s[i] == s[j]);}else {isPalindrome[i][j] = (s[i] == s[j] && isPalindrome[i+1][j-1]);}}}}

理解上还是有些难度,但是都读懂了。

拖稿了,抱歉,1个半点结束

《录鼎记》——重启之回溯part03相关推荐

  1. 《录鼎记》——重启之回溯part04

    今日任务: 93.复原IP地址 78.子集 90.子集II 一.复原IP地址 力扣题目链接 (opens new window) 如果说能想到和上到题一样是切割,就有基本的思路了. 回溯三部曲:1.递 ...

  2. 《录鼎记》——重启之回溯part05

    今日任务 * 491.递增子序列 * 46.全排列 * 47.全排列 II 一.递增子序列 力扣题目链接 (opens new window) class Solution { public:vect ...

  3. 刷题体验第一天——《录鼎记》第一章

    先来解释为啥用这个标题(除了蹭一点之外呢),第一个字,代表刷题的题目来源是<代码随想录>,而鼎有两种解释,一种是谐音顶(原谅作者现在还是个菜鸟),另一个也是时刻提醒自己,不能眼高手低,要切 ...

  4. 《录鼎记》第十三章——有史最长篇

    今日内容: 层序遍历 10 226.翻转二叉树 101.对称二叉树 2 一.二叉树的层序遍历 力扣题目链接 (opens new window) 思路一:队列实现,将根节点推入,之后在队列非空时,记录 ...

  5. 日知录(15):记药盒的串口通信

    十月中旬有一个答辩要去做,原本有点懈怠了,可想了想不能错过每个可以全力以赴的机会,所以硬着头皮继续刚. 我涉及到的主要是树莓派与arduino 的串口通信.想要实现的功能是在传送带上的药片经过颜色识别 ...

  6. 双录、可回溯政策再升级,元核云音视频产品护航金融交易合规高效

    2021年底,银保监在银保业务方面又有了重大举措,随着<中国银保监会办公厅关于做好银行代理保险业务整改工作有关事项的通知>的下发,正式提出银保远程双录的工作要求,在一定程度上放宽银保业务渠 ...

  7. 云信小课堂丨视频“双录”知多少?

    Vol. 11 随着互联网技术的日益进步,作为承担连接功能的音视频技术在金融行业发挥起了越来越大的作用,最常见的如视频银行.视频客服等. 音视频技术除了作为连接载体之外,其实还有一个很重要的功能,即记 ...

  8. UOS 录制电脑播放的音频 / 内录音频

    Windows 里面有一个"立体声混音",可以内录电脑播放的音频,而不受到外界噪音的干扰.前段时间接到反馈说 UOS 的设置里面的音频输入里面没有可以选择的设备,这里就稍微探索了一 ...

  9. 【2018.07.29】(深度优先搜索/回溯)学习DFS算法小记

    参考网站:https://blog.csdn.net/ldx19980108/article/details/76324307 这个网站里有动态图给我们体现BFS和DFS的区别:https://www ...

最新文章

  1. Linux下使用PPTP ×××拔号的实现
  2. 入门Java要学习的一些基本和高级工具
  3. STL源码剖析---vector
  4. 一步一步理解Paxos算法
  5. JUnit 5 –架构
  6. 【电路补习笔记】2、电容的参数与选型
  7. Windows下Subversion配置管理员指南
  8. 今天实现了一个功能就是,树结点的拖动
  9. Linux 的简单钩子
  10. CentOS7.5下KVM虚拟机安装
  11. 天涯社区用到的日历函数
  12. Android手机怎么打开exe,安卓手机如何打开.exe文件 安卓手机exe文件怎么打开
  13. Vijos训练计划 1-1 计数问题
  14. 财务软件服务器装什么系统,财务软件用哪种云服务器
  15. Qt之如何识别小键盘(数字键盘)
  16. 计算机桌面有边框阴影,“桌面图标下面有阴影的解决方案”的解决方案
  17. HTML+CSS打造简单的横向时间轴
  18. 计算机加入域用户名,将客户端计算机加入到域中
  19. 深信服上网行为管理(AC)、安全网关(SG)学习笔记
  20. openstack云计算平台<5>--核心组件配置->Netwoking服务

热门文章

  1. C Primer Plus 第六版 编程练习第四章答案 最新出炉
  2. 如何校验SQL查询结果是否准确
  3. 遍历List移除元素的若干种方法
  4. 国务院办公厅发文,电子签名、电子印章再迎利好
  5. 社群运营之微信群群规怎么写?
  6. AS-GCN 论文解读
  7. sublime text3083 破解 插件汉化
  8. 主动攻击与被动攻击的区别以及可靠性、可用性、保密性、完整性、不可抵赖性、可控性等的概念
  9. 中兴V880刷机后无法打开数据连接的解决
  10. 想进行Android和ios开发需要学会哪些语言