代码随想录算法训练营第23天|39. 组合总和、40.组合总和II、131.分割回文串

打卡Day23

  • 1.39. 组合总和
  • 2.40.组合总和II
  • 3.131.分割回文串

1.39. 组合总和

题目链接:39. 组合总和
文档讲解: 代码随想录

这道题和昨天做的组合之和由两个区别:被选的元素没有数量限制,同时被选的元素可以无限重复,只对总和进行限制。那么终止条件可以定为,和大于等于目标。单层逻辑,和组合之和一样的思路,只是在递归中不用 i + 1。最后是输入参数:整数数组、目标和、startindex(因为在一个数组里选择,避免重复)、和(记录遍历元素之和)、结果列表、路径列表。

class Solution(object):def combinationSum(self, candidates, target):""":type candidates: List[int]:type target: int:rtype: List[List[int]]"""res = []self.backtracking(candidates, target, 0, 0, res, [])return resdef backtracking(self, candidates, target, startindex, summ, res, path):#终止条件if summ > target:returnif summ == target:res.append(path[:])returnfor i in range(startindex, len(candidates)):path.append(candidates[i])summ += candidates[i]self.backtracking(candidates, target, i, summ, res, path)summ -= candidates[i]path.pop()

关于剪枝:如果加上本层递归的元素值,和已经大于目标值的情况,仍然会在进入下一层递归的时候才能判断和大于目标值,从而 return。因此,可以在本层判断是否加上本层元素值大于目标值来进行剪枝操作。一个非常重要的点就是,在进行递归前,需要将 candidates 数组进行排序。

class Solution(object):def combinationSum(self, candidates, target):""":type candidates: List[int]:type target: int:rtype: List[List[int]]"""res = []candidates.sort()self.backtracking(candidates, target, 0, 0, res, [])return resdef backtracking(self, candidates, target, startindex, summ, res, path):#终止条件if summ == target:res.append(path[:])returnfor i in range(startindex, len(candidates)):#剪枝if summ + candidates[i] > target:breakpath.append(candidates[i])summ += candidates[i]self.backtracking(candidates, target, i, summ, res, path)summ -= candidates[i]path.pop()

递归的第二个版本:与上一个版本的区别在于,不定义一个记录和的变量,使用 target 减去元素值,通过判断是否为0来终止递归。需要注意的是,终止条件包含两种情况:目标值为0,以及值小于0。

class Solution(object):def combinationSum(self, candidates, target):""":type candidates: List[int]:type target: int:rtype: List[List[int]]"""res = []self.backtracking(candidates, target, 0, res, [])return resdef backtracking(self, candidates, target, startindex, res, path):if target == 0:res.append(path[:])return if target < 0:returnfor i in range(startindex, len(candidates)):path.append(candidates[i])self.backtracking(candidates, target - candidates[i], i, res, path)path.pop()

剪枝版本:就是在进行下一层递归前判断是否减去本层值小于0。依然是需要排序。

class Solution(object):def combinationSum(self, candidates, target):""":type candidates: List[int]:type target: int:rtype: List[List[int]]"""res = []candidates.sort()self.backtracking(candidates, target, 0, res, [])return resdef backtracking(self, candidates, target, startindex, res, path):if target == 0:res.append(path[:])return for i in range(startindex, len(candidates)):if target - candidates[i] < 0:breakpath.append(candidates[i])self.backtracking(candidates, target - candidates[i], i, res, path)path.pop()

2.40.组合总和II

题目链接:40.组合总和II
文档讲解: 代码随想录

我的思路:和上一题不同的是,每个数字在每个组合中只能使用一次,只能使用一次的两个意思,递归时开始指针变为 i + 1,同时需要考虑到整型数组里有重复元素。那在开始前先进行排序,使用双指针的方法,用 pre 指针记住当前遍历的前一个元素,若相同直接 break 该层循环,从而达到去重的效果。没做出来,发现我理解错题目意思了,元素在同一个组合内是可以重复的,怎么重复都没事,但两个组合不能相同。这是我昨天的思路,我今天想到,这个是数组,不用 pre 指针,它可以通过 i - 1的下标来取前一个元素。这种思路会将例如 [1,1,6] 的组会去掉。

题解:整型数组里有重复元素,例如[10,1,2,7,4,1,6],目标值为8,第一个1和7组合,7和第二个1组合,这两个组合一样,需要去重。但第一个1,6,第二个1组合是允许的。因此,要去重的是同一树层上的相同元素,同一树枝上是一个组合里的元素,是可以重复的,因此不用去重。

在这里插入图片描述

class Solution(object):  def combinationSum2(self, candidates, target):""":type candidates: List[int]:type target: int:rtype: List[List[int]]"""candidates.sort()res = []self.backtracking(candidates, target, res, [], 0)return resdef backtracking(self, candidates, target, res, path, startindex):#终止条件if target == 0:res.append(path[:])return #结束函数for i in range(startindex, len(candidates)):#去重if i > startindex and candidates[i] == candidates[i - 1]:continue#结果该层for循环if target - candidates[i] < 0:break#结束for循环path.append(candidates[i])self.backtracking(candidates, target - candidates[i], res, path, i + 1)path.pop()
class Solution(object):  def combinationSum2(self, candidates, target):""":type candidates: List[int]:type target: int:rtype: List[List[int]]"""#使用used数组candidates.sort()uesd = [False] * len(candidates)res = []self.backtracking(candidates, target, uesd, res, [], 0)return resdef backtracking(self, candidates, target, used, res, path, startindex):if target == 0:res.append(path[:])returnfor i in range(startindex, len(candidates)):if i > startindex and candidates[i] == candidates[i - 1] and not used[i - 1]:continueif target - candidates[i] < 0:breakpath.append(candidates[i])used[i] = Trueself.backtracking(candidates, target - candidates[i], used, res, path, i + 1)path.pop()used[i] = False

3.131.分割回文串

题目链接:131.分割回文串
文档讲解: 代码随想录

这道题有如下几个难点:

(1)为什么切割问题可以抽象为组合问题
假设对于字符串abcde,切割问题思路是,先切割 a,再在bcde中切割第二段,切割 b 后,再切割第三段,这与组合的选取思路是类似的,因此可以抽象为组合问题

(2)如何模拟切割线
使用startindex表示切割线

(3)切割问题中递归如何终止
当遍历到字符串末尾时,则说明已经找到一种切割方法,每个叶子节点就是一种切割结果。因为本题中,切割出来的不是回文子串是不会向下递归的

(4)在递归循环中如何截取子串
从 startindex到 i 的范围就是切割出来的子串

(5)如何判断回文
使用双指针法,一个指针从前往后,一个指针从后往前,如果前后指针所指向的元素是相等的,则为回文子串

class Solution(object):def partition(self, s):""":type s: str:rtype: List[List[str]]"""res = []self.backtracking(s, 0, res, [])return resdef backtracking(self, s, startindex, res, path):#终止条件if startindex == len(s):res.append(path[:])returnfor i in range(startindex, len(s)):#判断是否为回文if self.ishuiwen(s, startindex, i):#是回文path.append(s[startindex:i + 1]) #左闭右开self.backtracking(s, i + 1, res, path)path.pop()def ishuiwen(self, s, left, right):#左闭右闭while left <= right:if s[left] != s[right]:return Falseleft += 1right -= 1return True

这道题的优化都是在优化判断是否为回文子串上。

class Solution(object):def partition(self, s):""":type s: str:rtype: List[List[str]]"""res = []self.backtracking(s, 0, res, [])return resdef backtracking(self, s, startindex, res, path):if startindex == len(s):res.append(path[:])returnfor i in range(startindex, len(s)):#是否为回文if s[startindex:i + 1] == s[startindex:i + 1][::-1]:path.append(s[startindex:i + 1])self.backtracking(s, i + 1, res, path)path.pop() 

具体来说,给定一个字符串 s,长度为 n,成为回文串的充分必要条件是 s[0] == s[n -1] 且 s[1:n - 1] 也是回文串,因此可以在回溯算法前,计算出 s 中所有子串是否为回文串,然后递归的时候直接查询就可以了。

class Solution(object):def partition(self, s):""":type s: str:rtype: List[List[str]]"""hwjuzhen = [[False] * len(s) for i in range(len(s))]self.huiwencom(s, hwjuzhen)res = []self.backtracking(s, 0, res, [], hwjuzhen)return resdef backtracking(self, s, startindex, res, path, hwjuzhen):if startindex == len(s):res.append(path[:])return for i in range(startindex, len(s)):if hwjuzhen[startindex][i]:path.append(s[startindex:i + 1])self.backtracking(s, i + 1, res, path, hwjuzhen)path.pop()def huiwencom(self, s, hwjuzhen):for i in range(len(s) - 1, -1, -1):for j in range(i, len(s)):if i == j:#单个字母必是回文串hwjuzhen[i][j] = Trueelif j - i == 1:#两个字母判断是否相同hwjuzhen[i][j] = (s[i] == s[j])else:hwjuzhen[i][j] = (s[i] == s[j] and hwjuzhen[i + 1][j - 1])

还可以使用python内置的 all 函数来判断是否回文。

class Solution(object):def partition(self, s):""":type s: str:rtype: List[List[str]]"""res = []self.backtracking(s, 0, res, [])return resdef backtracking(self, s, startindex, res, path):if startindex == len(s):res.append(path[:])returnfor i in range(startindex, len(s)):sub = s[startindex:i + 1]if self.ishuiwen(sub):path.append(s[startindex: i + 1])self.backtracking(s,i + 1, res, path)path.pop()def ishuiwen(self, s):return all(s[i] == s[len(s) - 1 -i] for i in range(len(s) // 2))

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

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

相关文章

JavaScript:节流与防抖

目录 一、前言 二、节流&#xff08;Throttle&#xff09; 1、定义 2、使用场景 3、实现原理 4、代码示例 5、封装节流函数 三、防抖&#xff08;Debounce&#xff09; 1、定义 2、使用场景 3、实现原理 4、代码示例 5、封装防抖函数 四、异同点总结 一、前言 …

Adobe Premiere Pro(Pr)安装包软件下载

一、简介 Adobe Premiere Pro&#xff08;简称Pr&#xff09;是由Adobe公司开发的一款功能强大的视频编辑软件。它支持多平台使用&#xff0c;包括Windows和Mac系统&#xff0c;并且拥有良好的兼容性和高效的性能。Premiere Pro不仅提供了视频剪辑、特效添加、音频处理等基本功…

《从C/C++到Java入门指南》- 9.字符和字符串

字符和字符串 字符类型 Java 中一个字符保存一个Unicode字符&#xff0c;所以一个中文和一个英文字母都占用两个字节。 // 计算1 .. 100 public class Hello {public static void main(String[] args) {char a A;char b 中;System.out.println(a);System.out.println(b)…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 二进制游戏(200分)- 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…

Transformer之Vision Transformer结构解读

论文地址 代码地址 写在前面 什么是Transformer呢&#xff1f;就是把符号向量化为Token&#xff0c; 再和位置编码求和或者做阿达玛积&#xff0c;最后送入一定层数的Attention Block构成的Encoder和Decoder&#xff0c;就完成了Transformer的基础功能。 那么&#xff0c;把上…

idea2019版本创建JavaWeb项目并配置Tomcat步骤

一、创建JavaWeb项目 1.新建项目File->New->Project 2. 选择JavaWeb应用在New Project窗口中选择Java后勾选Java EE中的Web Application后点击next即可 3.设置项目名称后点击finish即可 4.至此项目创建完成&#xff0c;检查文件是否齐全&#xff0c;开始配置Tomcat 二、…

IDEA工具中Java语言写小工具遇到的问题

一&#xff1a;读取excel时遇到 org/apache/poi/ss/usermodel/WorkbookProvider 解决办法&#xff1a; 在pom.xml中把poi的引文包放在最前面即可&#xff08;目前就算放在最后面也不报错了&#xff0c;不知道为啥&#xff09; 二&#xff1a;本地maven打包时&#xff0c;没有…

base SAS programing学习笔记(read raw files2)

使用COLUMN input和FORMATTED input读入固定位置的外部文件&#xff1b;如下图所示&#xff0c; 1.COLUMN input &#xff08;按列数读入外部文件数据&#xff09; 使用column input 不需要按从左到右的顺序读取外部文件的数值&#xff0c;可以是任意读取&#xff0c;也可以重…

STM32F103定时器中断详解

目录 目录 目录 前言 一.什么是定时器 1.1 STM32F103定时器概述 1.2基本定时器 1.2通用定时器 1.3高级定时器 1.4 三种定时器区别 基本定时器&#xff08;Basic Timer&#xff09; 通用定时器&#xff08;General-Purpose Timer&#xff09; 高级定时器&#xff08;Advanced Ti…

ubuntu2204配置anacondacuda4090nvidia驱动

背景 某个机房的几台机器前段时间通过dnat暴露至公网后被入侵挖矿&#xff0c;为避免一些安全隐患将这几台机器执行重装系统操作&#xff1b; 这里主要记录配置nvidia驱动及cuda&anaconda。 步骤 大概分为几个步骤 禁用nouveau配置grub显示菜单install nvidia-driveri…

基于Python+Django,开发的一个在线教育系统

一、项目简介 使用Python的web框架Django进行开发的一个在线教育系统&#xff01; 二、所需要的环境与组件 Python3.6 Django1.11.7 Pymysql Mysql pure_pagination DjangoUeditor captcha xadmin crispy_forms 三、安装 1. 下载项目后进入项目目录cd Online-educ…

配置RIPv2的认证

目录 一、配置IP地址、默认网关、启用端口 1. 路由器R1 2. 路由器R2 3. 路由器R3 4. Server1 5. Server2 二、搭建RIPv2网络 1. R1配置RIPv2 2. R2配置RIPv2 3. Server1 ping Server2 4. Server2 ping Server1 三、模拟网络攻击&#xff0c;为R3配置RIPv2 四、在R…

Linux:Linux权限

目录 1. Linux权限的概念 2. Linux权限管理 2.1 文件访问者的分类 2.2 文件类型和访问权限 2.2.1 文件类型 2.2.2 基本权限 2.3 文件权限值的表示方法 2.4 文件访问权限的相关设置方法 2.4.1 chmod 2.4.2 chown 2.4.3 chgrp 2.4.4 umask 3. file指令 4. Linux目…

base SAS programming学习笔记13(Array)

1.Array array-name{dimension} <elements> array-name&#xff1a;向量名称 dimension&#xff1a;向量长度&#xff0c;默认为1&#xff1b; elements:列出变量名&#xff0c;变量名要么全是数值变量或者全是字符变量 array-name和variable不能相同&#xff1b;也不能和…

C++面试题之判断一个变量是不是指针

对于变量其实对应的就是内存&#xff0c;而内存并没有表明一定是什么数据类型&#xff0c;所以判断变量是否是一个指针其实是一个参数类型匹配问题&#xff0c;在C中支持函数的重载&#xff0c;那么不同的函数因为参数的不同从而匹配不同函数调用过程。 编译器在进行函数匹配调…

JAVA周总结(集合) 0721day

一.Collection集合 集合:可以存放多种类型数据的容器。 集合和数组的区别 数组的长度是固定的,集合的长度根据存储的数据发生改变。 数组只能存同一种类型的数组,而集合可以存多种类型。 1.2 单列集合常用类的继承体系 java.util.List: 添加的元素是有序、可重复 ; Lis…

PostgreSQL简介和安装

一、Postgresql简介&#xff1a; 1、PostgreSql是功能强大的&#xff0c;开源的关系型数据库&#xff0c;底层基于C语言实现&#xff1b; 2、开源&#xff1a;允许对PostgreSql进行封装&#xff0c;用于商业收费&#xff1b; 3、版本迭代速度快&#xff0c;正式版本已经到15.R…

【轻松拿捏】java中为什么要使用克隆?如何实现对象克隆?深拷贝和浅拷贝区别是什么?

java中为什么要使用克隆&#xff1f;如何实现对象克隆&#xff1f;深拷贝和浅拷贝区别是什么&#xff1f; 一、如何在Java中实现对象克隆 1.1 浅拷贝 1.2 深拷贝 1.3 区别总结 二、面试回答技巧 1. 定义克隆及其用途 2. 解释浅拷贝和深拷贝 3. 具体实现浅拷贝和深拷贝 …

【Python】使用库 -- 详解

库就是别人已经写好了的代码&#xff0c;可以让我们直接拿来用。 一个编程语言能不能流行起来&#xff0c;一方面取决于语法是否简单方便容易学习&#xff0c;一方面取决于生态是否完备。所谓的 “生态” 指的就是语言是否有足够丰富的库&#xff0c;来应对各种各样的场景。在…

LeetCode 188题: 买卖股票的最佳时机IV优化(原创)

之前完成了LeetCode 188题&#xff1a; 买卖股票的最佳时机IV&#xff08;原创&#xff09;-CSDN博客&#xff0c;虽然完成代码编写&#xff0c;并提交成功&#xff0c;但运行效率还未达到最优的1ms&#xff0c;见下图&#xff1a; 仔细检查代码&#xff0c;感觉还是有可优化的…