代码随想录算法训练营第二十六天 | 39. 组合总和,40.组合总和II, 131.分割回文串[回溯篇]

代码随想录算法训练营第二十六天

  • LeetCode 39. 组合总和
    • 题目描述
    • 思路
    • 参考代码
    • 总结
  • LeetCode 40.组合总和II
    • 题目描述
    • 思路
    • 参考代码
  • LeetCode 131.分割回文串
    • 题目描述
    • 思路
      • 切割问题
      • 回文判断
    • 参考代码
    • 总结


LeetCode 39. 组合总和

题目链接:39. 组合总和
文章讲解:代码随想录#39. 组合总和
视频讲解:带你学透回溯算法-组合总和(对应「leetcode」力扣题目:39.组合总和)| 回溯法精讲!

题目描述

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

示例1

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

示例2

candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

示例3

输入: candidates = [2], target = 1
输出: []

提示

  • 1 <= candidates.length <= 30
  • 2 <= candidates[i] <= 40
  • candidates 的所有元素 互不相同
  • 1 <= target <= 40

思路

同一个数字可以无限制重复使用,这和之前 77.组合 不太一样,所以每次递归遍历时,索引不需要+1。
target作为递归函数的终止条件。

也可以做一些剪枝的操作,比如前sum之和大于target时直接返回。

参考代码

/*** Return an array of arrays of size *returnSize.* The sizes of the arrays are returned as *returnColumnSizes array.* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().*/int **res;
int cnt;
int sum;
typedef struct {int index;int nums[30];
}Data;
Data data = {0};void backtracking(int* candidates, int candidatesSize, int target, int** returnColumnSizes, int idx)
{if (sum == target) {res[cnt] = (int *)malloc(data.index * sizeof(int));for (int i = 0; i < data.index; i++) {res[cnt][i] = data.nums[i]; }(*returnColumnSizes)[cnt] = data.index;cnt++;return;}for (int i = idx; i < candidatesSize; i++) {if (sum + candidates[i] > target) continue; // 剪枝,跳过当前循环data.nums[data.index++] = candidates[i];sum += candidates[i];backtracking(candidates, candidatesSize, target, returnColumnSizes, i);sum -= candidates[i]; // 回溯data.index--;data.nums[data.index] = 0;}
}int** combinationSum(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes) {res = (int**)malloc(1000 * sizeof(int));*returnColumnSizes = (int*)malloc(sizeof(int) * 200);cnt = 0;sum = 0;backtracking(candidates, candidatesSize, target, returnColumnSizes, 0);*returnSize = cnt;return res;
}

总结

  1. 对于返回值以及returnColumnSizes的初始化时,空间大小不好选择,我每次都是试出来了,这个不太好。

LeetCode 40.组合总和II

题目链接:40.组合总和II
文章讲解:代码随想录#40.组合总和II
视频讲解:回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II

题目描述

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。

示例1

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

示例2

输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]

提示

  • 1 <= candidates.length <= 100
  • 1 <= candidates[i] <= 50
  • 1 <= target <= 30

思路

需要注意几个点如下:

  • candidates 数组中的每个数字在每个组合中只能使用一次。
  • candidates 数组中的元素会有重复的。

这道题我们需要考虑去重的情况了。
所谓去重,其实就是使用过的元素不能重复使用。
那应该如何去重呢?
①首先对candidates 数组进行从小到大的排序,相同的数值的元素就连在一起了。
②构造一个与candidates 数组大小相同的used数组,用来表示元素是否使用过。
具体思路可以查看代码随想录。

我盗用两张图说明一下重复的情况。
在这里插入图片描述
在这里插入图片描述
在candidates[i] == candidates[i - 1]相同的情况下:

  • used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
  • used[i - 1] == false,说明同一树层candidates[i - 1]使用过

参考代码

int cnt;
int sum;
int* used;
int** ret;
typedef struct {int index;int nums[100];
} Data;
Data data = {0};int cmp(const void* p1, const void* p2) { return *(int*)p1 - *(int*)p2; }void backtracking(int* candidates, int candidatesSize, int target, int** returnColumnSizes, int idx) {if (sum == target) {ret[cnt] = malloc(sizeof(int) * data.index);for (int i = 0; i < data.index; i++)ret[cnt][i] = data.nums[i];(*returnColumnSizes)[cnt] = data.index;cnt++;return;}for (int i = idx; i < candidatesSize; i++) {if (sum + candidates[i] > target) // 剪枝操作break;// 当前执行到i,如果used[i - 1] == 0,说明candidates[i - 1]已经使用过了,直接跳过// 如果看不懂,可以多看看随想录的思路,然后自已在本地推导几遍if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == 0) continue;sum += candidates[i];data.nums[data.index++] = candidates[i];used[i] = 1;// 必须是i+1,下一层的循环跳过当前层的元素,指向下一个元素backtracking(candidates, candidatesSize, target, returnColumnSizes, i + 1);sum -= candidates[i]; // 回溯data.index--;data.nums[data.index] = 0;used[i] = 0;}
}int** combinationSum2(int* candidates, int candidatesSize, int target,int* returnSize, int** returnColumnSizes) {ret = (int**)malloc(10000 * sizeof(int*));used = (int*)malloc(100 * sizeof(int));*returnColumnSizes = (int*)malloc(sizeof(int) * 100);for (int i = 0; i < 100; i++) // 清空used数组used[i] = 0;cnt = 0;sum = 0;// 排序,将相同值的元素挨在一起qsort(candidates, candidatesSize, sizeof(int), cmp);backtracking(candidates, candidatesSize, target, returnColumnSizes, 0);*returnSize = cnt;return ret;
}

LeetCode 131.分割回文串

题目链接:[131.分割回文串 (https://leetcode.cn/problems/palindrome-partitioning/)
文章讲解:代码随想录#131.分割回文串
视频讲解:带你学透回溯算法-分割回文串(对应力扣题目:131.分割回文串)| 回溯法精讲!

题目描述

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

回文串 是正着读和反着读都一样的字符串。

示例1

输入:s = “aab”
输出:[[“a”,“a”,“b”],[“aa”,“b”]]

示例2

输入:s = “a”
输出:[[“a”]]

提示

  • 1 <= s.length <= 16
  • s 仅由小写英文字母组成

思路

看完题目描述后没有一点儿思路,还是得看一遍视频。
本题有两个关键点:
①字符串切割,可以使用回溯法进行不同方式的切割。
②对切割好的子串进行回文判断,如果是回文,则添加到返回的变量中。

切割问题

其实切割问题,可以采用回溯法进行切割,终止条件就是切割到了字符串的最后一个字符。
递归函数的返回值为void,参数有两个,一个是原字符串,另一个当前层遍历的起始位置idx。

在单层搜索的逻辑中会有一个for循环,相当于对树进行横向遍历,i的起始值为idx,i的终止值为strlen(s)。
首先对以idx/i为起始的字符串进行处理(第一层),
如果[idx, i]的子串为回文,则将子串添加到res变量中,
调用递归函数,对以i+1为起始的字符串进行处理(第二层)。。。
递归函数处理完后,进行回溯操作,然后对i+1继续下一次遍历。
如果不是回文,在同一层i+1继续遍历。

借用一张图说明一下树状关系:
在这里插入图片描述

回文判断

可以使用双指针法,一个从头向尾,一个从尾向前开始遍历,如果前后指针指向的元素相等,则说明是回文字符串。

参考代码

char*** partition(char* s, int* returnSize, int** returnColumnSizes) {// 待实现
}

总结

  1. 这道题的复杂之处就是要对收集的结果赋值给一个三维指针,时间有限,我暂时还没有想清楚,后面补上。

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

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

相关文章

Mysql5.7主从复制搭建

注意不适用Mysql8 Docker搭建Mysql主从复制 docker run -p 3307:3306 --name mysql-master \ -v /usr/local/develop/mysql-master/log:/var/log/mysql \ -v /usr/local/develop/mysql-master/data:/var/lib/mysql \ -v /usr/local/develop/mysql-master/conf:/etc/mysql/con…

10 在线逻辑分析仪的使用

在线逻辑分析仪简介 传统的 FPGA 板级调试是将逻辑分析仪连接到 FPGA 的 IO 引脚上 &#xff0c;然后将内部信号引出至 IO 引脚&#xff0c;再进行板级调试&#xff0c;这种方法的缺点是我们需要一个逻辑分析仪&#xff0c;且还要在 PCB 中预留测试点。在线逻辑分析仪克服了以…

博途PLC PID仿真(单容水箱液位高度控制含变积分变增益测试)

单容水箱和双荣水箱的微分方程和数值求解,可以参考下面文章链接: https://rxxw-control.blog.csdn.net/article/details/131139432https://rxxw-control.blog.csdn.net/article/details/131139432这篇博客我们利用欧拉求解器在PLC里完成单容水箱的数学建模。PLC也可以和MATL…

Python习题详解

练习&#xff1a; 1&#xff0c;计算100以内奇数的和 #计算100以内所有奇数的和 sum 0 # n 1 # while n < 100: # # sum sum n # sum n # # n n 2 # n 2 # print(sum) n 99 #求偶数时n 100 while n > 0:sum n# n n - 2n - 2 print(sum)2&#xff0c;打印直…

【办公类-22-08】周计划系列(4)“育儿知识(家园小报)“ (2024年调整版本)

作品展示 背景需求&#xff1a; 制作“育儿知识&#xff08;家园小报&#xff09;”&#xff0c;查询发现去年就没有做 因为“家园小报”基本没有段落文字&#xff0c;都是“文本框文字、艺术字“&#xff0c;很难用python提取文字。 由于只有6篇&#xff0c;因此去年采用的就…

【线程池项目(四)】项目的死锁问题分析和资源回收机制的改善

在上一篇 【线程池项目&#xff08;三&#xff09;】线程池CACHED模式的实现中我们大概说了说cached模式的基本实现&#xff0c;对于多线程编程&#xff0c;我们需要考虑的问题也较于单线程更多、更复杂&#xff0c;经常存在线程同步、资源竞争等复杂的并发控制问题&#xff0c…

【Java程序设计】【C00276】基于Springboot的就业信息管理系统(有论文)

基于Springboot的就业信息管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的就业信息管理系统 本系统分为前台功能模块、管理员功能模块、学生功能模块、企业功能模块以及导师功能模块。 前台功能模块&…

微服务知识02

1、九大高并发解决方案 2、系统架构图​​​​​​​ 3、分布式事务 本地事务、分布式事务 操作不同服务器的数据库&#xff08;垂直分库&#xff09; 4、分布式事务解决方案&#xff08;没有seata之前&#xff09; &#xff08;1&#xff09;XA协议&#xff08;强一致性&a…

PixPin:一键搞定截图、长截图、贴图、GIF

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、什么是PixPin&#xff1f;①PixPin②核心功…

readproc.h

Ubuntu22.04系统中 编译自己写的程序的时候&#xff0c;报错&#xff0c;显示找不到readproc.h文件&#xff0c;通过安装libprocps-dev解决 sudo apt install libprocps-dev

项目解决方案:街道社区视频监控接入、汇聚和联网设计方案

目 录 一、客户需求 二、网络拓扑图 三、方案描述 四、系统配置 1、服务器配置 2、带宽配置 五、方案优势 1. 平台可堆叠使用 2. 支持主流接入协议 4. 多种终端显示 5. 客户端功能强大 6. 一机一档 一、客户需求 1&#xff0c;一个街道有十个社…

消息中间件篇之RabbitMQ-高可用机制

一、怎么保证高可用性 在生产环境下&#xff0c;使用集群来保证高可用性&#xff0c;一般我们采用普通集群、镜像集群、仲裁队列。 二、普通集群 普通集群&#xff0c;或者叫标准集群&#xff08;classic cluster&#xff09;&#xff0c;具备下列特征&#xff1a; 1. 会在集…

蓝桥杯DP算法——区间DP(C++)

根据题意要求的是将石子合并的最小权值&#xff0c;我们可以根据DP思想使用二维数组f[i,j]来存放所有从第i堆石子到第j堆石子合并成一堆石子的合并方式。 然后由第二个图所示&#xff0c;我们可以将i到j区间分成两个区间&#xff0c;因为将i到j合并成一个区间的前一步一定是合…

SpringBoot自动装配的原理

废话不多说&#xff0c;直接上干货 SpringBoot 是如何实现自动装配的&#xff1f; 以我这个2.6.13的版本为例 第一步&#xff0c;我们先从SpringBootApplication这个入口注解看起 在springBootApplication这个注解当中有三个关键性的注解&#xff0c;大概可以看作是&#xff1a…

Java面试:Spring Cloud Alibaba

文章目录 引言I Spring Cloud Alibaba1.1 配置文件加载的优先级(由高到低)1.2 注册中心1.3 rpcII 高并发场景:缓存穿透/缓存失效/雪崩如何解决2.1 缓存穿透2.2 缓存击穿(失效)2.3 缓存雪崩引言 微服务涉及的中间件分布式事务事务的传播方式事务的隔离级别缓存穿透/缓存失效…

Matlab/simulink基于vsg的风光储调频系统建模仿真(持续更新)

​ 1.Matlab/simulink基于vsg的风光储调频系统建模仿真&#xff08;持续更新&#xff09;

C/C++暴力/枚举/穷举题目持续更新(刷蓝桥杯基础题的进!)

目录 前言 一、百钱买百鸡 二、百元兑钞 三、门牌号码&#xff08;蓝桥杯真题&#xff09; 四、相乘&#xff08;蓝桥杯真题&#xff09; 五、卡片拼数字&#xff08;蓝桥杯真题&#xff09; 六、货物摆放&#xff08;蓝桥杯真题&#xff09; 七、最短路径&#xff08;蓝…

图解目标检测 之 【YOLOv9】 算法 最全原理详解

YOLOv9与SOTA模型对比 什么是 YOLOv9&#xff1f;YOLOv9是YOLO系列中的最新产品&#xff0c;是一种实时目标检测模型。它通过先进的深度学习技术和架构设计&#xff0c;包括通用 ELAN (GELAN) 和可编程梯度信息 (PGI)&#xff0c;展现出更好的性能。 YOLO 系列通过引入计算机视…

Java/Python/Go不同开发语言基础数据结构和相关操作总结-GC篇

Java/Python/Go不同开发语言基础数据结构和相关操作总结 1. 常见gc方式1.1 gc判断对象是否存活1.2 引用计数法1.2 标记-清除算法1.3 复制算法1.4 标记-压缩算法1.5 分代收集算法 2. java的gc方式以及垃圾回收器2.1 gc方式2.1 gc回收器2.1.1 Serial收集器2.1.2 ParNew收集器2.1.…

Socket、UDP、TCP协议和简单实现基于UDP的客户端服务端

目录 Socket TCP和UDP区别 UDP&#xff1a;无连接&#xff0c;不可靠传输&#xff0c;面向数据报&#xff0c;全双工 TCP&#xff1a;有连接&#xff0c;可靠传输&#xff0c;面向字节流&#xff0c;全双工 无连接和有连接 可靠传输和不可靠传输 面向数据报和面向字节流…