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

代码随想录第23天第24天 | 回溯 (二)

39. 组合总和

题目链接/文章讲解:组合总和

class Solution {
public:vector<vector<int>> res;vector<int> vec;void f(vector<int>& candidates, int target,int start){if(target==0){res.push_back(vec);return;}if (target < 0) {return; // 剪枝:目标值已为负,不可能满足}for(int i=start;i<candidates.size();i++){//这里也可来个剪枝if(target<candidates[i]) continue;target-=candidates[i];vec.push_back(candidates[i]);f(candidates,target,i);//即然可以重复则这里的开始位置就定为itarget+=candidates[i];vec.pop_back();}}vector<vector<int>> combinationSum(vector<int>& candidates, int target) {//这题和一般组合的区别在于可以重复使用里面的元素f(candidates,target,0);return res;}
};

40.组合总和II

这题的重难点在于保证所有方案不一致,如何去重?因为数组中有相同的元素,所以和其他题目去重的思路不太一致。

题目链接/文章讲解:组合总和II

举个例子【10 1 2 7 6 1 5】我们把它排序看一下【1 1 2 5 6 7 10】

之前说过任何的回溯问题都可以抽象为树结构,这题当然很好去抽象过去, 第一次取1,作为根节点的左子树,接着再取1,同理也可第一次取2,再取剩余的数组

则这样分析出来取数导致最终结果重复,其实是由于每一层有重复的元素,比如第一次取第一个1,第二三次取2和5,也可以第一次取第二个1,第二三次取2和5.

说明是每一次(抽象为树的层)取的数字相同就会导致重复。

那每一次层取的时候可以有一个used数组,在递归前把要取的数先看一下是否和used里的元素有相同的,若有则不取。

注意代码里取看是否有重复的是看used[i-1]是否为false,若为则需要跳过,因为说明前面的相同元素已经有过这个情况了,若再选这个则会出现重复现象。

class Solution {
public:vector<vector<int>> res;vector<int> vec;void f(vector<int>& candidates, int target,int start,vector<bool>& used){if(target==0){res.push_back(vec);return;}if (target < 0 || start >= candidates.size()) {return;  // 添加边界条件检查}for(int i=start;i<candidates.size();i++){if(i>0 && candidates[i] == candidates[i - 1] && used[i - 1] == false){//这里的candidate是为了确保前后两个数一样再判断是否需要跳过continue;}vec.push_back(candidates[i]);used[i]=true;f(candidates,target-candidates[i],i+1,used);vec.pop_back();used[i]=false;}}vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {sort(candidates.begin(),candidates.end());vector<bool> used(candidates.size(), false);f(candidates,target,0,used);return res;}
};

131.分割回文串

本题属于分割问题

分割回文串

class Solution {
public:vector<vector<string>> res;vector<string> vec;//每次遍历的结果bool isPalindrome(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 f(string s,int start){//结束条件if(start>=s.size()){res.push_back(vec);return;}//具体的遍历思路:for(int i=start;i<s.size();i++){if(isPalindrome(s, start, i)){string p= s.substr(start , i - start  + 1);vec.push_back(p);}else{continue;}f(s,i+1);vec.pop_back();}}vector<vector<string>> partition(string s) {//先进行遍历再去判断是否为回文串,若为则放入结果数组中f(s,0);return res;}
};

93.复原IP地址

题目链接/文章讲解:复原IP地址

class Solution {
public:vector<string> res;void f(string& s,int start,int count){if(count==0){if (valid(s, start , s.size() - 1)) {res.push_back(s);}return;}for(int i=start;i<s.size();i++){if(valid(s, start, i)){s.insert(s.begin() + i + 1 , '.');f(s,i+2,count-1);//这里是+2,因为前面加了一个.s.erase(s.begin() + i + 1);//函数}else{break;}}}bool valid(const string& s, int start, int end) {if (start > end) {return false;}if (s[start] == '0' && start != end) { // 0开头的数字不合法return false;}int num = 0;for (int i = start; i <= end; i++) {if (s[i] > '9' || s[i] < '0') { // 遇到非数字字符不合法return false;}num = num * 10 + (s[i] - '0');if (num > 255) { // 如果大于255了不合法return false;}}return true;}vector<string> restoreIpAddresses(string s) {//有效IP地址由四个整数来组成,意思是这个字符串要分成四份,每一份要符合要求f(s,0,3);return res;}
};

78.子集

所谓去重,其实就是使用过的元素不能重复选取

子集问题,就是收集树形结构中,每一个节点的结果。 整体代码其实和 回溯模板都是差不多的。

题目链接/文章讲解:子集

class Solution {
public:vector<vector<int>> res;//res.push_back({});vector<int> v;void f(vector<int> nums,int start){res.push_back(v);for(int i=start;i<nums.size();i++){v.push_back(nums[i]);f(nums,i+1);v.pop_back();}}vector<vector<int>> subsets(vector<int>& nums) {//返回子集//首先是空集,再接着遍历f(nums,0);return res;}
};

90.子集II

大家之前做了 40.组合总和II 和 78.子集 ,本题就是这两道题目的结合。

题目链接/文章讲解:子集II

class Solution {
public:vector<vector<int>> res;vector<int> v;void f(vector<int> nums,int start,vector<bool> used){res.push_back(v);for(int i=start;i<nums.size();i++){if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false){continue;}v.push_back(nums[i]);used[i] = true;f(nums,i+1,used);v.pop_back();used[i] = false;}}vector<vector<int>> subsetsWithDup(vector<int>& nums) {//返回子集但是元素中有重复元素sort(nums.begin(),nums.end());vector<bool> used(nums.size(), false);//初始化f(nums,0,used);return res;}
};

491.递增子序列

这题长得很像前面的,但实际上去重逻辑不同,有坑。

递增子序列

之前的去重是去重同一层不能有相同的元素则用used[i-1]=false,而这个去重是同一父节点下的元素不能相同。这就要每一个父节点就需要有一个去重的数组。

这里用unordered_set来操作

由于其查找速度快且set本身就去重

class Solution {
public://同一父节点下的同层上使用过的元素就不能再使用了vector<vector<int>> res;vector<int> v;void f(vector<int>& nums,int start){if(v.size()>=2){res.push_back(v);//return;不能return否则只输出两个元素的情况}unordered_set<int> used; // 使用set来对本层元素进行去重for(int i=start;i<nums.size();i++){if(!v.empty() && nums[i] < v.back()|| used.find(nums[i]) != used.end()){//如果找到了,返回指向该元素的迭代器,若没找到则返回.end()continue;}used.insert(nums[i]);v.push_back(nums[i]);f(nums,i+1);v.pop_back();}}vector<vector<int>> findSubsequences(vector<int>& nums) {//找出不同递增(非严格递增)子序列,且最少两个元素f(nums,0);return res;}
};

http://www.dtcms.com/a/419409.html

相关文章:

  • 初始化VUE3项目
  • [C++项目框架库]redis的简单介绍和使用
  • redis特性和应用场景
  • 手机网站建设制作wordpress2019谷歌字体
  • 网站建设一个月多少钱网站图片设置教程
  • Linux零基础入门:权限与常用命令详解
  • 【Pyzmq】python 跨进程线程通信 跨平台跨服务器通信
  • 科技企业网站建设网站建设咨询什么
  • K8s部署与NodePort暴露全指南
  • 数据结构 02 线性表
  • 建设工商联网站的意义湟源县网站建设
  • 浙江网站建设技术公司淘宝客商品推广网站建设
  • 【HarmonyOS】鸿蒙应用实现微信分享-最新版
  • 房地产项目网站建设方案做外贸的网站简称为什么网站
  • Vue 3 开发的 HLS 视频流播放组件+异常处理
  • 前端核心框架vue之(路由核心案例篇3/5)
  • vue中不同的watch方法的坑
  • 网站首页排版设计广州网络公关公司
  • 批量重命名技巧:使用PowerShell一键整理图片文件命名规范
  • 手机版网站怎么做的企业解决方案架构师
  • 网站企业备案改个人备案专业微网站制作
  • 新天力科技以创新驱动发展,铸就食品包装容器行业领军者
  • crew AI笔记[7] - flow特性示例
  • 广州制作网站公司网站开发收税
  • 二阶可降阶微分方程的求解方法总结
  • 纯静态企业网站模板免费下载手机app编程
  • Redis在高并发场景中的核心优势
  • 教育网站 网页赏析网络营销推广的优缺点
  • 金溪县建设局网站品牌网站怎么建立
  • 中国气候政策不确定性数据(2000-2022)