数据结构算法刷题(27)回溯(子集型)

news2024/11/25 22:37:07

回溯思想:

思路:这种出现全部xx组合的,基本都是回溯算法。首先,当digits是空,那返回也是空。当回溯到边界条件的时候,就更新答案,在非边界条件的时候,循环该数值下的全部情况。

class Solution:

    def letterCombinations(self, digits: str) -> List[str]:

        dict_letter = {'2':['a','b','c'],

                        '3':['d','e','f'],

                        '4':['g','h','i'],

                        '5':['j','k','l'],

                        '6':['m','n','o'],

                        '7':['p','q','r','s'],

                        '8':['t','u','v'],

                        '9':['w','x','y','z']}

        if len(digits) == 0:

            return []

        ans = []

        def letter(path,num): #将每次的新组合传递下去

            if len(num) == 0: #何时停止递,更新答案?

                ans.append(path)

                return

            for c in dict_letter[num[0]]: #循环的子问题

                letter(path+c,num[1:])

        letter('',digits)

        return ans

子集型回溯:

 

思路:对于nums中的每一个数字,都有选和不选两种可能,一共有n次选择的机会,用n来控制递归,每选择一次,就给n减一再去递归,直到n是0,就要将path写入答案。注意path是全局变量,要用copy固定答案,以及某一次选择子集之后,要恢复现场。(退回到根节点)

class Solution:

    def subsets(self, nums: List[int]) -> List[List[int]]:

        ans = []

        path = []

        n = len(nums)

        def sets(n):

            if n == 0:

                ans.append(path.copy())#固定答案

                return

            sets(n-1) #不选该子集,直接递归

            path.append(nums[n-1]) #选该子集

            sets(n-1) #选该子集

            path.pop() #恢复现场

        sets(n)

        return ans

 

思路一:遍历子串的结束位置,对于每一个传入的i,遍历子串的结束位置,如果是回文串,就加入path中,然后继续递归之后的子串。

class Solution:

    def partition(self, s: str) -> List[List[str]]:

        ans = []

        path = []

        n = len(s)

        def part(i): #子串的开始位置

            if i == n:

                ans.append(path.copy())

                return

            for j in range(i,n):#遍历子串的结束位置

                t = s[i:j+1]

                if t == t[::-1]: #是回文串

                    path.append(t)

                    part(j+1) #递归剩下的子串

                    path.pop()#恢复现场

        part(0)

        return ans

思路二:假设每个字母之间存在一个逗号,每次遇到逗号都要选择或者不选择。当不选择逗号时,初始位置start不变,但是终止位置i+1(i截止到n-1),当选择逗号时,意味着从逗号处开始分割,取此时的s[start:i+1],判断是否是回文串,如果是,就加入到path中,继续递归剩下的字符串(s[i+1:],开始位置和结束位置都重新设置为i+1),递归之后要恢复现场。

class Solution:

    def partition(self, s: str) -> List[List[str]]:

        ans = []

        path = []

        n = len(s)

        def part(start,i): #子串的开始位置,结束的位置

            if i == n:

                ans.append(path.copy())

                return

            #不选择逗号

            if i < n-1:

                part(start,i+1) #只增加结束位置

            #选择逗号

            t = s[start:i+1] #取当前分割的字符串

            if t == t[::-1]: #是回文串

                path.append(t)

                part(i+1,i+1) #递归剩下的子串

                path.pop()#恢复现场

        part(0,0)

        return ans

 思路一:对于每个s[i]选择反转或者选择不反转

class Solution:

    def letterCasePermutation(self, s: str) -> List[str]:

        ans = []

        n = len(s)

        def bfs(i,path): #将层数和路径一起传递下去

            if i == n:

                ans.append(path)

                return

            #选择不反转

            bfs(i+1,path+s[i])

            #选择反转

            if 'a' <= s[i] <= 'z' or 'A' <= s[i] <= 'Z':

                bfs(i+1,path+s[i].swapcase())

        bfs(0,'')

        return ans

 思路二:枚举s[i]判断是否是字母并修改,由于没有包含不修改选项,所以递归入口处就要把答案写进去,然后对剩下的字符串修改。

class Solution:

    def letterCasePermutation(self, s: str) -> List[str]:

        ans = []

        n = len(s)

        path = list(s)

        def bfs(i):

            ans.append(''.join(path)) #先写入答案

            if i == n:

                return

            for j in range(i,n):#枚举下标并修改

                if 'a' <= s[j] <= 'z' or 'A' <= s[j] <= 'Z':

                    path[j] = path[j].swapcase() #修改

                    bfs(j+1) #递归

                    path[j] = path[j].swapcase() #恢复现场

        bfs(0)

        return ans

思路:按照由简单到复杂的顺序来思考这个题:我们需要一个path来存储满足累加序列的list或者是只有两个元素的list。首先我们假设path不需要任何限制条件,就是找num的全部分割子集(代码中的橘色部分),然后我们需要考虑到,如果一个数首位是0,就不符合分割,加一个限制条件。然后我们path中要求满足累加,把path分成两种情况,第一种是有了两个元素了,就要判断是否满足累加,满足就加到path中。另一种情况是不足两个元素,那就直接加到path中,不需要判断。最后在递归的边界条件,要判断一下,path是否是大于两个元素,大于才能放入ans中。

class Solution:

    def isAdditiveNumber(self, num: str) -> bool:

        ans = []

        path = []

        n = len(num)

        if n < 3:

            return False

        def dfs(i):

            if i == n:

                if len(path) >= 3: #长度大于2才能放入ans

                    ans.append(path.copy())

                return

            for j in range(i, n):

                t = num[i:j+1]

                if len(t) > 1 and t[0] == '0': #不符合分割的限制条件

                    continue

                if len(path) >= 2:

                    if path[-1] + path[-2] == int(t): #是否满足累加

                        path.append(int(t))

                        dfs(j+1)

                        path.pop()

                if len(path) < 2: #直接加到path中,不需要判断

                    path.append(int(t))

                    dfs(j+1)

                    path.pop()

        dfs(0)

        return len(ans) > 0

     

 思路:对于[1,n]中的数字,每一个我们都要判断一下是否是符合

设置一个函数sumi,如果函数返回true,就符合,那就将其平方和加入答案中。sumi中先分割i*i的十进制,在边界条件中判断path和是否是i,是就加入ans,最后输出len(ans) > 0.。

class Solution:

    def sumi(self,i):

        power2 = str(i*i)

        ans = []

        path = []

        n = len(power2)

        def dfs(a):

            nonlocal i

            if a == n:

                if sum(path) == i:

                    ans.append(path.copy())

                return

            for j in range(a,n):

                t = power2[a:j+1]

                path.append(int(t))

                dfs(j+1)

                path.pop()

        dfs(0)

        return len(ans) > 0

    def punishmentNumber(self, n: int) -> int:

        ans = 0

        for i in range(1,n+1):

            if self.sumi(i):

                ans += i*i

        return ans

思路:将问题拆分开,我们首先计算出[0,len(mat[0])](一共多少列)有多少种可能的不重复的子集 (橘色),这些子集中,我们需要的path长度是cols,当长度符合时,去更新答案。对于任何一个确定的子集,计算行的和是否等于被覆盖的数的和,是则更新答案。

class Solution:

    def rows(self,path,matrix):

        ans = 0

        for i in matrix:

            sumj = 0

            for j in path:

                sumj += i[j] #被覆盖的数的和

            if sum(i) == sumj: #行和是否等于被覆盖的数和

                ans += 1 #被覆盖的行数

        return ans

    def maximumRows(self, matrix, numSelect: int) -> int:

        res = -1

        path = []

        nums = [i for i in range(len(matrix[0]))] #求nums的可能子集

        def dfs(i):

            nonlocal res,path,nums

            if i == len(nums):

                if len(path) == numSelect: #当子集长度符合时,更新答案

                    res = max(self.rows(path.copy(),matrix),res)

                return

            dfs(i+1) #选

            path.append(i) #不选

            dfs(i+1)

            path.pop()

        dfs(0)

        return res

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

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

相关文章

125760-33-0,Fmoc-Thr(Ac4Galβ1-3Ac2GalNAcα)-OH,于蛋白质糖基化修饰

文章关键词&#xff1a;糖化学试剂&#xff0c;化学试剂&#xff0c;糖基氨基酸一、试剂基团反应特点&#xff08;Reagent group reaction characteristics&#xff09;&#xff1a; Fmoc-Thr(Ac4Galβ1-3Ac2GalNAcα)-OH中蛋白质糖基化修饰是在糖基转移酶的催化作用下糖链分子…

色环电阻介绍

复习一下色环电阻&#xff0c;是在电阻封装上(即电阻表面)涂上一定颜色的色环&#xff0c;来代表这个电阻的阻值。色环实际上是早期为了帮助人们分辨不同阻值而设定的标准。色环电阻现在应用还是很广泛的&#xff0c;如家用电器、电子仪表、电子设备中常常可以见到。但由于色环…

Java内存模型(JMM)和volatile原理

一、Java 内存模型 JMM即Java Memory Model&#xff0c;他定义了主存&#xff08;共享的数据&#xff09;、工作内存&#xff08;私有的数据&#xff09;抽象概念&#xff0c;底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等 JMM体现以下几个方面 原子性-保证指令不会受…

ad18报错:Minimum Solder Mask Sliver Constraint

报告上提示&#xff1a; Minimum Solder Mask Sliver (Gap0.254mm) (All),(All) Minimum Solder Mask Sliver Constraint&#xff0c;PCB焊盘阻焊层之间间距小于0.254报错 修改了这里&#xff0c;把这个报警值改小一些&#xff0c;就不会报警了 翻译过来是&#xff1a;最小…

8.vue3医疗在线问诊项目 - _问诊室模块-websocket学习 ==> 消息卡片、websocket、socket.io、约定通讯规则、建立连接

8.vue3医疗在线问诊项目 - _问诊室模块-websocket学习 &#xff1e; 消息卡片、websocket、socket.io、约定通讯规则、建立连接 问诊室-路由与组件 目标&#xff1a;配置路由和分析结构 1&#xff09;路由配置 {path: /room,component: () > import(/views/room/index.vue)…

UNIX网络编程卷一 学习笔记 第二十章 广播

本书迄今为止的所有例子都是单播&#xff1a;一个进程与另一个进程通信。TCP只支持单播寻址&#xff0c;而UDP和原始IP还支持其他寻址类型&#xff0c;下图比较了不同的寻址方式&#xff1a; IPv6往寻址体系中增加了任播&#xff08;anycasting&#xff09;方式。RFC 1546讲述…

章节5:04-shiro反序列化漏洞

章节5&#xff1a;04-shiro反序列化漏洞 复现环境 本地tomcat或Docker vulhub 基础环境&#xff1a; IDEA Maven Tomcat Burp JDK8版 01 Shiro介绍 Shiro Apache Shiro&#xff1a;开源安全框架 身份验证授权会话管理加密 本地代码 https://github.com/apache/shi…

Iptables防火墙策略

目录 一、iptables netfilter/iptables 关系 二、四表五链 三、iptables的安装 iptables 命令行配置方法 管理选项 一、iptables Linux 系统的防火墙——netfilter/iptables IP信息包过滤系统&#xff0c;它实际上由两个组件netfilter 和 iptables组成。 主要工作在网络…

MATLAB与大数据:如何应对海量数据的处理和分析

第一章&#xff1a;引言 在当今数字化时代&#xff0c;大数据已经成为了各行各业的核心资源之一。海量的数据源源不断地涌现&#xff0c;如何高效地处理和分析这些数据已经成为了许多企业和研究机构面临的重要挑战。作为一种功能强大的数学软件工具&#xff0c;MATLAB为我们提供…

深度剖析InnoDB存储结构

大家都知道 MySQL 的数据都是存储在物理磁盘上的&#xff0c;那具体是保存在哪个文件呢&#xff1f;我们首先要知道MySQL 存储的行为是由存储引擎实现的&#xff0c;不同的存储引擎保存的文件自然也不同。由于InnoDB 是我们常用的存储引擎&#xff0c;也是 MySQL 默认的存储引擎…

Spring Cloud Alibaba - Sentinel源码分析(二)

目录 一、Sentinel源码分析 1、时间窗算法 2、滑动时间窗算法 3、Sentinel滑动时间窗口算法源码解析 4、Sentinel滑动窗口数据统计源码解析 一、Sentinel源码分析 1、时间窗算法 时间窗算法&#xff0c;也可以称之为&#xff1a;固定时间窗算法 概念&#xff1a;固定时…

015:vue项目中常用的正则表达式

第015个 查看专栏目录: VUE — element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使用…

【RV1126】使用gpiolib框架

文章目录 史上最简单&#xff1a;增加GPIO控制功能是如何实现的呢&#xff1f;GPIOLIB框架Linux 驱动实现 控制引脚输出高低电平综合测试 这一套非常方便&#xff01; 史上最简单&#xff1a;增加GPIO控制功能 如果是想增加GPIO控制只需要修改设备树就可以做到&#xff01; …

谷粒商城第二天-项目环境搭建

目录 一、前言 二、学习的内容 一、虚拟平台的安装&#xff0c;远程连接虚拟机的工具的安装 二、Docker以及常用软件的安装 一、安装Docker&#xff1a; 二、安装相关软件 三、开发环境的统一 1. 这里就是调整Maven的下载依赖的地址&#xff0c;改用阿里云镜像地址 2. …

11.vue3医疗在线问诊项目 - _药品订单 ==> 支付页面、支付详情、支付结果、订单详情、物流信息、高德地图工具

11.vue3医疗在线问诊项目 - _药品订单 &#xff1e; 支付页面、支付详情、支付结果、订单详情、物流信息、高德地图工具 药品订单-支付页面-路由 目标&#xff1a;配置路由&#xff0c;分析药品支付组件结构 1&#xff09;路由与组件 {path: /medicine/pay,component: () >…

系列十一、MongoDB副本集

一、概述 MongoDB副本集&#xff08;Replica Set&#xff09;是有自动故障恢复功能的主从集群&#xff0c;有一个Primary节点和一个或者多个Secondary节点组成。副本集没有固定的主节点&#xff0c;当主节点发生故障时&#xff0c;整个集群会选举一个主节点 为系统提供服务以保…

大数据测试基本知识

常用大数据框架结构 1.大数据测试常用到的软件工具 工具推荐&#xff0c;对于测试数据构造工具有&#xff1a;Datafaker、DbSchema、Online test data generator等&#xff1b;ETL测试工具有&#xff1a;RightData、QuerySurge等&#xff1b;数据质量检查工具&#xff1a;great…

SpringBoot医药管理系统设计+第三稿+文档

博主介绍&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 项目名称 SpringBoot医药管理系统设计第三稿文档 视频演示 SpringBoot医药管理系统设计第三稿中期检查表ppt外文文献翻译文献综述开题任务书查重报告安装视频讲…

【计算机网络】第五章数据链路层-电子科技大学2023期末考试

第五章 数据链路层 学习目的 目的1&#xff1a;理解链路层服务的主要功能 差错检查、纠错 共享广播信道&#xff1a;多点接入问题(multiple access) 链路层寻址(link layer addressing) 局域网技术&#xff1a;Ethernet, VLANs 目的2&#xff1a;链路层技术的实现 点到点…

【Java入门】-- Java基础详解之【程序控制结构】

目录 1.程序流程控制介绍 2.顺序控制 3.分支控制if-else 4.嵌套分支 5.switch分支语句 6.for循环控制&#xff08;重点&#xff09; 7.while循环控制 8.do...while循环控制 9.多重循环控制&#xff08;重难点&#xff01;&#xff09; 10.跳转控制语句break 11.跳转…