代码随想录|Day23|回溯03|39.组合总和、40.组合总和II、131.分割回文串

39.组合总和

本题和 216.组合总和III 类似,但有几个区别:

  1. 没有元素个数限制:树的深度并不固定,因此递归终止条件有所变化
  2. 每个元素可以使用多次:下层递归的起始位置和上层相同(startIndex不需要改动)

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        
        def backtrack(startIndex, path, currentSum):
            # 和大于等于目标的时候终止
            # 如果等于目标,还需要先收集
            if currentSum >= target:
                if currentSum == target:
                    result.append(path[:])
                return
            
            for i in range(startIndex, len(candidates)):
                path.append(candidates[i])
                currentSum += candidates[i]
                # 下层递归的起始位置和本层相同
                backtrack(i, path, currentSum)
                path.pop()
                currentSum -= candidates[i]
        
        result = []
        backtrack(startIndex = 0, path = [], currentSum = 0)
        return result

 剪枝:如果我们事先对 candidates 排序,那么下一层递归的 currentSum 一定会更大,在此之前判断 currentSumtarget 的判断可以实现剪枝。

为什么要排序?举个例子,假设总和为 4,那么 [2, 2] 符合条件,下一次搜索可能获得 [2, 1, 1] 也是符合条件的,如果排序则可以确保接下来搜索的元素更大,换句话说 [2, 1, 1] 一定在 [2, 2] 之前被找到。

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        
        def backtrack(startIndex, path, currentSum):
            # 和大于等于目标的时候终止
            # 如果等于目标,还需要先收集
            if currentSum >= target:
                if currentSum == target:
                    result.append(path[:])
                return
            
            for i in range(startIndex, len(candidates)):
                # 剪枝:如果和已经超过,则不需要继续搜索
                if currentSum + candidates[i] > target: continue

                path.append(candidates[i])
                currentSum += candidates[i]
                # 下层递归的起始位置和本层相同
                backtrack(i, path, currentSum)
                path.pop()
                currentSum -= candidates[i]
        
        result = []
        candidates.sort()
        backtrack(startIndex = 0, path = [], currentSum = 0)
        return result

40.组合总和II

本题的关键是 candidates 中的元素可能重复,如果使用传统的方法递归,则结果很有可能包含重复组合。举个例子,假设 candidates = [1, 2, 2, 5]target = 3。当我们选择了 1,其递归出现 3个 分支:[1, 2]、[1, 2]、[1, 5],此时出现了重复组合。

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:

        def backtrack(startIndex, path, currentSum):
            if currentSum >= target:
                if currentSum == target:
                    result.append(path[:])
                return
            
            for i in range(startIndex, len(candidates)):
                # 如果当前数字与前一个数字相同,并且不是遍历的第一个数字,则跳过以避免重复组合
                if i > startIndex and candidates[i] == candidates [i-1]:
                    continue
                # 剪枝
                if currentSum + candidates[i] > target:
                    return                

                path.append(candidates[i])
                currentSum += candidates[i]

                backtrack(i + 1, path, currentSum)

                path.pop()
                currentSum -= candidates[i]
        
        result = []
        # 排序
        candidates.sort()
        backtrack(startIndex = 0, path = [], currentSum = 0)
        return result

131.分割回文串

本题可以理解为一个组合问题,我们组合不同的元素,判断是否为回文子串。 

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        # 双指针判断是否为回文串
        def isPalindrome(subs):
            left, right = 0, len(subs)-1
            while left < right:
                if subs[left] != subs[right]:
                    return False
                left += 1
                right -= 1
            return True
        
        def backtrack(startIndex, path):
            # startIndex是我们的切割线
            # 因此递归终止条件为切割到末尾
            if startIndex >= len(s):
                result.append(path[:])
                return
            
            for i in range(startIndex, len(s)):
                # [startIndex, i]为我们的切割子串
                if isPalindrome(s[startIndex: i+1]):
                    path.append(s[startIndex: i+1])
                    backtrack(i+1, path)
                    path.pop()
            
        result = []
        backtrack(startIndex = 0, path = [])
        return result

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

接口测试常见接口类型?

常见接口类型 1.根据协议区分 1、webService接口:是走soap协议通过http传输请求报文和返回报文都是xml格式的&#xff0c;我们在测试的时候都用通过工具才能进行调用&#xff0c;测试。可以使用的工具有Soapul、jmeter、loadrunner等; 2、http接口:是走http协议&#xff0c;…

Python爬虫在Django项目中的数据处理与展示实例

当谈到Python爬虫技术与Django项目结合时&#xff0c;我们面临着一个引人入胜又具有挑战性的任务——如何利用爬虫技术从网络上抓取数据&#xff0c;并将这些数据进行有效地处理和展示。在本文中&#xff0c;我将为您介绍Python爬虫技术在Django项目中的数据抓取与处理流程。 在…

Java-JVM 虚拟机原理调优实战

一、基础 栈帧&#xff08;Stack Frame&#xff09;栈空间的 基本元素&#xff0c;用于 方法的调用和方法的执行的数据结构 堆内存用来存放由new创建的对象和数组。在堆中分配的内存&#xff0c;由Java虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或对象后&#xff0c…

Linux 管道

目录 一、认识管道 二、匿名管道 pipe函数 用法&#xff1a; pipefd&#xff1a; 匿名管道通信&#xff1a; 三、命名管道 概念&#xff1a; 创建&#xff1a; 特性&#xff1a; 用途&#xff1a; 四、命名管道和匿名管道的区别 命名&#xff1a; 持久性&#xff1a;…

汽车电子拓扑架构的演进过程

汽车电子拓扑架构的演进过程 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师 (Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,喝完再挣扎,出门靠…

系统渐渐沦为“屎山”,这就是真相!

分享是最有效的学习方式。 博客&#xff1a;https://blog.ktdaddy.com/ 背景 小猫维护现有的系统也有一段时间了&#xff0c;踩坑也不少&#xff0c;事故不少。感兴趣的小伙伴可以了解一下&#xff0c;往期的小猫踩坑记合集。 这天&#xff0c;小猫找到了商城系统的第一任开发…

Springboot-软件授权License

无意中看到了一个简单方便的授权方式&#xff0c;只需几步就可集成到boot项目中。 先上地址&#xff1a;smart-license: 保护个人与企业的软件作品权益&#xff0c;降低盗版造成的损失。PS&#xff1a;因个人精力有限&#xff0c;不再提供该项目的咨询答疑服务。 Smart-licen…

Smart Light Random Memory Sprays Retinex 传统图像增强 SLRMSR

文章目录 前言1、Smart Light Random Memory Sprays Retinex概况2、Smart Light Random Memory Sprays Retinex的实现2.1、SLRMSR算法的伪代码2.2、初始化记忆喷雾&#xff08;CreateInitialMemorySpray&#xff09;2.3、更新记忆喷雾 (UpdateMemorySpray)2.4、计算颜色校正因子…

二十几岁的我们:在旷野中找寻自我

二十几岁&#xff0c;这是一个充满变数、充满机遇和挑战的年纪。它如同一片辽阔的旷野&#xff0c;每个人都在其中寻找自己的方向&#xff0c;摸索着自己的道路。这是一个既令人兴奋又令人迷茫的年纪&#xff0c;我们穿着不同的鞋子&#xff0c;注定要走不同的路。 在这个年纪里…

onnx 格式模型可视化工具

onnx 格式模型可视化工具 0. 引言1. 可视化工具2. 安装 Netron: Viewer for ONNX models 0. 引言 ONNX 是一种开放格式&#xff0c;用于表示机器学习模型。ONNX 定义了一组通用运算符&#xff08;机器学习和深度学习模型的构建基块&#xff09;和通用文件格式&#xff0c;使 A…

Unity引擎是否被过度吹嘘?

提到Unity&#xff0c;人们基本上持有以下几种观点&#xff1a; A. 很多人十分欣赏Unity在跨平台兼容性和大规模开放世界场景方面的出色表现。其渲染、环境特效以及AI系统为设计多样化沙盒游戏提供了强大支持。这使得Unity非常适合开发具有多种游戏玩法和互动系统的作品。 B. 一…

Java有哪些常用的集合?

1、典型回答 在 Java 中&#xff0c;常用的集合有以下几个&#xff1a; 列表(List)&#xff1a;有序集合&#xff0c;可以包含重复元素。常见实现类有 ArrayList、LinkedList、 Vector 等集合(Set)&#xff1a;无序集合&#xff0c;不允许包含重复元素。常见实现类有 HashSet、…

【复现】【免费】基于多时间尺度滚动优化的多能源微网双层调度模型

目录 主要内容 部分代码 结果一览 1.原文结果 2.程序运行结果 下载链接 主要内容 该模型参考《Collaborative Autonomous Optimization of Interconnected Multi-Energy Systems with Two-Stage Transactive Control Framework》&#xff0c;主要解决的是一个…

深入了解JVM底层原理

一、JVM内存结构 1、方法区&#xff1a;存储编译后的类、常量等&#xff08;.class字节码文件&#xff09; 2、堆内存&#xff1a;存储对象 3、程序计数器&#xff1a;存储当前执行的指令地址&#xff08;计算机处理器&#xff08;CPU&#xff09;正在执行的下一条指令在内存…

win修改图标自定义QQ桌面图标

当安装了TIM后&#xff0c;想把图标改成QQ 图标见顶部&#xff0c;或通过网盘下载 提取码&#xff1a;9Ayc 操作步骤&#xff1a; 1.桌面右键图标&#xff0c;点击属性 2.选择快捷方式-更改图标 3.浏览选择下载的ico图标即可

Python中的迭代器与生成器提高性能的秘密武器【第143篇—迭代器与生成器】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Python中的迭代器与生成器&#xff1a;提高性能的秘密武器 在Python编程中&#xff0c;迭代…

17双体系Java学习之数组的长度

数组的长度 //获取数组长度 arrays.lengthfor (int i 0; i <nums.length; i) {sum sum nums[i];}System.out.println("总和为&#xff1b;"sum);

心灵治愈交流平台|基于springboot框架+ Mysql+Java+B/S结构的心灵治愈交流平台设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 管理员功能登录前台功能效果图 用户功能模块 心理咨询师功能 系统功能设计 数据库…

Linux下使用ntpdate进行时间同步

1.简介 ntpdate是Linux下用于从NTP服务器同步时间的命令行工具。 2.安装 大多数Linux发行版已预装ntpdate。未安装的可使用以下命令&#xff1a; # Ubuntu/Debian sudo apt-get install ntpdate # CentOS/Fedora/RHEL sudo yum install ntpdate 3.手工同步网络时间 执行以下命…

操作系统原理与实验——实验七固定分区的分配与回收

实验指南 运行环境&#xff1a; Dev c 算法思想&#xff1a; 本实验是模拟存储管理方式中的固定分区分配与回收算法&#xff0c;系统在作业装入前预分将整个用户区划分为若干个大小确定的分区&#xff0c;然后根据待装入作业的名称和大小到分区列表中查找满足要求的空闲分区&am…