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

代码随想录算法训练营day23

代码随想录算法训练营

—day23

文章目录

  • 代码随想录算法训练营
  • 前言
  • 一、39. 组合总和
  • 二、40.组合总和II
  • 三、131.分割回文串
  • 总结


前言

今天是算法营的第23天,希望自己能够坚持下来!
今日任务:
● 39. 组合总和
● 40.组合总和II
● 131.分割回文串


一、39. 组合总和

题目链接
文章讲解
视频讲解

在这里插入图片描述

思路:

  1. 递归函数的参数和返回值:参数:整数数组 candidates,目标整数 target,总和sum,遍历的开始索引startIndex。
  2. 终止条件:本题对path的大小没有限制,只有总和的限制,当总和=target的时候结束,将path放入结果集。
  3. 单层递归的逻辑:纵向遍历可以重复使用数字,所以for循环中递归用的是i(若不重复则是i+1)。
  4. 去重:先将数组排序,如果sum+candidates[i]>target那么后面的元素都会大于target,所以for循环的终止条件可以加上这个,提前退出循环。
class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {if (sum == target) { //总和等于目标值则加入结果集result.push_back(path);return;}//如果sum+candidates[i]>target就终止遍历for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i ++) {sum += candidates[i];path.push_back(candidates[i]);backtracking(candidates, target, sum, i); //这里因为同一个数字可以重复使用,所以用startIndex是isum -= candidates[i]; //回溯path.pop_back(); //回溯}return;}vector<vector<int>> combinationSum(vector<int>& candidates, int target) {path.clear();result.clear();sort(candidates.begin(), candidates.end()); //需要排序if (candidates.size() == 0) return result;backtracking(candidates, target, 0, 0);return result;}
};

二、40.组合总和II

题目链接
文章讲解
视频讲解

这道题目和39.组合总和 (opens new window)如下区别:
1.本题candidates 中的每个数字在每个组合中只能使用一次。
2.本题数组candidates的元素是有重复的,而39.组合总和 (opens new window)是无重复元素的数组candidates
最后本题和39.组合总和 (opens new window)要求一样,解集不能包含重复的组合。

本题的难点在于区别2中:集合(数组candidates)有重复元素,但还不能有重复的组合。

本题是多加了一个used数组,去记录纵向遍历时使用过的数字。
在这里插入图片描述

树层去重的话,需要对数组排序!

思路:

  1. 递归函数参数以及返回值:参数数组candidates,目标值target,总和sum,索引startIndex,标记使用过的数字数组used。
  2. 终止条件:sum == target
  3. 单层处理逻辑:当前元素与前一位元素相等,且是前一位元素没用过,也就是以当前元素(重复元素)开始寻找新的结果,跳过这次循环

代码如下:

class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracking(vector<int>& candidates, int target, int sum, int startIndex, vector<bool>& used){if (sum == target) {result.push_back(path);return;}for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i ++) {//当前元素与前一位元素相等,且是前一位元素没用过,也就是以当前元素开始寻找新的结果,跳过这次循环if (i > 0 && candidates[i] == candidates[i-1] && used[i-1] == false) continue; //去重path.push_back(candidates[i]);sum += candidates[i];used[i] = true; //记录使用当前结果path用了那些元素backtracking(candidates, target, sum, i + 1, used); //candidates里的数字只能用一次,i+1sum -= candidates[i];path.pop_back();used[i] = false;}}vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {vector<bool> used (candidates.size(), false);path.clear();result.clear();//需要把candidates排序,让相同的元素挨在一起sort(candidates.begin(), candidates.end());if (candidates.size() == 0) return result;backtracking(candidates, target, 0, 0, used);return result;}
};

三、131.分割回文串

题目链接
文章讲解
视频讲解

在这里插入图片描述
跟组合问题类似,递归遍历每个字符串的位置去切割,每一种结果都是一种多个切割点的组合。只是每次切割都需要判断切割后是否为回文字符子串,是则放入path,继续切割,否则继续遍历寻找合适的切割点。

思路:

  1. 递归函数的参数:传入字符串s,遍历索引startIndex
  2. 终止条件:startIndex已经到达字符串尾端(将判断回文放在了for循环中,这里直接放入结果集)
  3. 单层递归的逻辑:[startIndex,i]就是本次截取的字符串,判断其是否回文,是则加入path中,否则continue去寻找合适的切割点。递归寻找i+1为起始位置的子串。
class Solution {
public:vector<string> path; //放已经回文的子串vector<vector<string>> result;void backtracking(string& s, int startIndex) {if (startIndex >= s.size()) {result.push_back(path);return;}for (int i = startIndex; i < s.size(); i++) {if (isPalindrome(s, startIndex, i)) {  //判断[startIndex,i]之间的字符串是否为回文子串//是则截取出来,放入pathstring str = s.substr(startIndex, i - startIndex + 1); //substr是左闭右开区间所以+1path.push_back(str);} else {continue; //不是回文则跳过}backtracking(s, i + 1); //递归寻找i+1为起始位置的子串path.pop_back(); //回溯}}//双指针判断是否为回文子串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;}vector<vector<string>> partition(string s) {result.clear();path.clear();if (s.size() == 0) return result;backtracking(s, 0);return result;}
};

总结

1.今天第一次涉及到去重,去重又分树枝(纵向)去重和树层(横向)去重。可以使用used数组去标记使用过的元素。
2.分割问题跟组合问题类似,也是求不同分割点的组合。在for循环中判断是否符合切割要求。

明天继续加油!


http://www.mrgr.cn/news/82746.html

相关文章:

  • 创建型模式4.原型模式
  • 引领实时数据分析新时代:阿里云实时数仓 Hologres
  • 条款08:别让异常逃离析构函数
  • (leetcode算法题)137. 只出现一次的数字 II
  • uniapp-vue3 实现, 一款带有丝滑动画效果的单选框组件,支持微信小程序、H5等多端
  • K8s高可用集群之Kubernetes集群管理平台、命令补全工具、资源监控工具部署及常用命令
  • 安装Linux
  • Oracle Dataguard(主库为单节点)配置详解(3):配置备库
  • 力扣【SQL连续问题】
  • App窗口创建流程(Android12 )
  • (已开源-AAAI25) RCTrans:雷达相机融合3D目标检测模型
  • 【设计模式-1】软件设计模式概述
  • 【Python】绿色便携版Python制作(发布)方法
  • Oracle Dataguard(主库为单节点)配置详解(2):配置主库
  • 智能工厂的设计软件 应用场景的一个例子: 为AI聊天工具添加一个知识系统 之21 再次重建 之6 整“拼” 项目文档+程序框架 总述
  • 【Linux】函数
  • 1.2.1-2部分数据结构的说明02_链表
  • 简历_专业技能_熟悉分布式锁Redisson的原理以及使用
  • QML学习(七) 学习QML时,用好Qt设计器,快速了解各个组件的属性
  • 使用Dinky快速提交Flink operator任务
  • Elasticsearch 入门教程
  • Unity2D初级背包设计中篇 MVC分层撰写(万字详解)
  • 音视频-----RTSP协议 音视频编解码
  • VisualRules规则引擎语法介绍
  • Linux(Ubuntu24.04)源码编译安装VTK7.1.1记录
  • 源代码编译安装X11及相关库、vim,配置vim(2)