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

news2024/12/23 13:49:09

打卡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 res

    def backtracking(self, candidates, target, startindex, summ, res, path):
        #终止条件
        if summ > target:
            return
        if summ == target:
            res.append(path[:])
            return
        
        for 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 res

    def backtracking(self, candidates, target, startindex, summ, res, path):
        #终止条件
        if summ == target:
            res.append(path[:])
            return
        
        for i in range(startindex, len(candidates)):
            #剪枝
            if summ + candidates[i] > target:
                break

            path.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 res
        
    def backtracking(self, candidates, target, startindex, res, path):
        if target == 0:
            res.append(path[:])
            return 

        if target < 0:
            return
        
        for 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 res
        
    def 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:
                break

            path.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 res
       
    def 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 res

    def backtracking(self, candidates, target, used, 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] and not used[i - 1]:
                continue
            if target - candidates[i] < 0:
                break
            path.append(candidates[i])
            used[i] = True
            self.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 res

    def backtracking(self, s, startindex, res, path):
        #终止条件
        if startindex == len(s):
            res.append(path[:])
            return
        
        for 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 False
            left += 1
            right -= 1
        return True

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

class Solution(object):
    def partition(self, s):
        """
        :type s: str
        :rtype: List[List[str]]
        """
        res = []
        self.backtracking(s, 0, res, [])
        return res
        
    def backtracking(self, s, startindex, res, path):
        if startindex == len(s):
            res.append(path[:])
            return
        
        for 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 res

    def 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] = True
                elif 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 res

    def backtracking(self, s, startindex, res, path):
        if startindex == len(s):
            res.append(path[:])
            return
        for 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.coloradmin.cn/o/1939574.html

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

相关文章

区块链技术实现数字电网内数据可信共享 |《超话区块链》直播预告

随着全球电力市场朝着构建“SmartGrid”和“IntelliGrid”的目标发展&#xff0c;国内电力公司也提出了构建“数字电网”的愿景。清大科越推出新型电力系统区块链服务平台&#xff0c;通过便捷的建链、上链、用链及治链能力&#xff0c;有效解决数字电网各主体间数据共享的信任…

QT--网络篇

如果QT头文件找不到QTcpSocket、QTcpSocket、QTcpServer、QtNetwork ,那么可能是pro文件中缺少QT network这行代码 客户端QTcpSocket void QTcpSocket::connectToHost( QString servip, quint16 port ); connectToHost 函数会尝试与指定的服务器建立 TCP 连接。如果连接成…

代码随想录算法训练营第35天|LeetCode 01背包问题 二维、01背包问题 一维、416. 分割等和子集

1. LeetCode 01背包问题 二维 题目链接&#xff1a;https://kamacoder.com/problempage.php?pid1046 文章链接&#xff1a;https://programmercarl.com/背包理论基础01背包-1.html#算法公开课 视频链接&#xff1a;https://www.bilibili.com/video/BV1cg411g7Y6/ 思路&#xf…

【Vue】`v-if` 指令详解:条件渲染的高效实现

文章目录 一、v-if 指令概述二、v-if 的基本用法1. 基本用法2. 使用 v-else3. 使用 v-else-if 三、v-if 指令的高级用法1. 与 v-for 一起使用2. v-if 的性能优化 四、v-if 的常见应用场景1. 表单验证2. 弹窗控制 五、v-if 指令的注意事项 Vue.js 是一个用于构建用户界面的渐进式…

在 PostgreSQL 里如何实现数据的冷热数据分层存储的自动化策略调整?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 在 PostgreSQL 里如何实现数据的冷热数据分层存储的自动化策略调整 在 PostgreSQL 里如何实现数据的冷…

最新可用度盘不限速后台系统源码_去授权开心版

某宝同款度盘不限速后台系统源码&#xff0c;验证已被我去除&#xff0c;两个后端系统&#xff0c;账号和卡密系统 第一步安装宝塔&#xff0c;部署卡密系统&#xff0c;需要环境php7.4 把源码丢进去&#xff0c;设置php7.4&#xff0c;和伪静态为thinkphp直接访问安装就行 …

bootstrap中文文档官网

Bootstrap v3 中文文档 Bootstrap 是最受欢迎的 HTML、CSS 和 JavaScript 框架&#xff0c;用于开发响应式布局、移动设备优先的 WEB 项目。 | Bootstrap 中文网

PostgreSQL 中如何解决因大量并发删除和插入操作导致的索引抖动?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 PostgreSQL 中如何解决因大量并发删除和插入操作导致的索引抖动一、理解索引抖动二、索引抖动的影响三…

C语言:温度转换

1.题目&#xff1a;实现摄氏度&#xff08;Celsius&#xff09;和华氏度&#xff08;Fahrenheit&#xff09;之间的转换。 输入一个华氏温度&#xff0c;输出摄氏温度&#xff0c;结果保留两位小数。 2.思路&#xff1a;&#xff08;这是固定公式&#xff0c;其中 F 是华氏度&a…

DL/T645-2007_Part1(协议帧解析)

帧结构 起始字符68H地址域起始字符68H控制码C数据域长度L数据域校验和CS结束字符16H1Byte6Byte1Byte1Byte1ByteN Byte1Byte1Byte 地址域 地址域为6个字节的BCD码构成&#xff0c;当使用的地址码长度不足6字节&#xff0c;高位用0补足&#xff1b;当通信地址为99999999999H时…

自学 阿里巴巴Java开发手册最新版(嵩山版)

&#x1f534; 阿里巴巴Java开发手册最新版&#xff08;嵩山版&#xff09; 一、编程规约(一) 命名风格(二) 常量定义(三) 代码格式(四) OOP 规约(五) 日期时间(六) 集合处理(七) 并发处理(八) 控制语句(九) 注释规约(十) 前后端规范 二、异常日志(一) 错误码(二) 异常处理(三)…

【BUG】已解决:python setup.py bdist_wheel did not run successfully.

已解决&#xff1a;python setup.py bdist_wheel did not run successfully. 目录 已解决&#xff1a;python setup.py bdist_wheel did not run successfully. 【常见模块错误】 解决办法&#xff1a; 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主…

自动驾驶-预测概览

通过生成一条路径来预测一个物体的行为&#xff0c;在每一个时间段内&#xff0c;为每一辆汽车重新计算预测他们新生成的路径&#xff0c;这些预测路径为规划阶段做出决策提供了必要信息 预测路径有实时性的要求&#xff0c;预测模块能够学习新的行为。我们可以使用多源的数据…

NetSuite Saved Search迁移工具

我们需要在系统间迁移Saved Search&#xff0c;但是采用Copy To Account或者Bundle时&#xff0c;会有一些Translation不能迁移&#xff0c;或者很多莫名其妙的Dependency&#xff0c;导致迁移失败。因此&#xff0c;我们想另辟蹊径&#xff0c;借助代码完成Saved Search的迁移…

数据库事务隔离级别及底层原理详解

本文详细记录了数据库中事务的隔离级别及其定义&#xff0c;以及每个隔离级别下可能会遇到哪些问题及对应的解决方案和原理&#xff0c;以下内容结合为各大平台的知识点加自己的理解进行的总结&#xff0c;希望大家在读完以后能对事务有个全新的认识~~ 1. MySQL事务管理 自动…

Connecting weaviate with langflow across docker containers

题意&#xff1a;在Docker容器之间连接Weaviate与Langflow 问题背景&#xff1a; I am trying to build a local RAG application using Langflow. For my vectore store, I want to use a local Weaviate instance, hosted in a separate docker container on the same netwo…

使用dock构建基于lnmp的WrodPress

项目要求&#xff1a; 1.创建nginx容器环境 上传nginx.conf文件、上传阿里云镜像、上传html目录 2.准备mysql cd /opt mkdir mysql 上传my.conf文件、上传阿里云镜像、写好的Dockfile文件 3.准备php cd /opt mkdir php 上传所需文件&#xff1a; 构建各镜像&#xff1a; …

【艺术向】【素描创作记录】《如何为你的红颜知己创作一幅画像(之二)》

写在前面 之前分析过类似的创作过程&#xff0c;见博客【艺术向】【素描创作记录】《如何为你的红颜知己创作一幅画像》 本人业余时间修习素描多年&#xff0c;在此撰文记录《如何为你的红颜知己创作一幅画像&#xff08;之二&#xff09;》&#xff0c;博得对方好感&#xff…

JQuery+HTML+JavaScript:实现地图位置选取和地址模糊查询

本文详细讲解了如何使用 JQueryHTMLJavaScript 实现移动端页面中的地图位置选取功能。本文逐步展示了如何构建基本的地图页面&#xff0c;如何通过点击地图获取经纬度和地理信息&#xff0c;以及如何实现模糊查询地址并在地图上标注。最后&#xff0c;提供了完整的代码示例&…

【proteus经典实战】LCD滚动显示汉字

一、简介 Proteus是一款功能丰富的电子设计和仿真软件&#xff0c;它允许用户设计电路图、进行PCB布局&#xff0c;并在虚拟环境中测试电路功能。这款软件广泛应用于教育和产品原型设计&#xff0c;特别适合于快速原型制作和电路设计教育。Proteus的3D可视化功能使得设计更加直…