Python算法题集_组合总和

 Python算法题集_组合总和

  • 题39:组合总和
  • 1. 示例说明
  • 2. 题目解析
    • - 题意分解
    • - 优化思路
    • - 测量工具
  • 3. 代码展开
    • 1) 标准求解【值传递+回溯】
    • 2) 改进版一【引用传递+堆栈回溯】
    • 3) 改进版二【过程值列表缓存+遍历后检索】
  • 4. 最优算法
  • 5. 相关资源

本文为Python算法题集之一的代码示例

题39:组合总和

1. 示例说明

  • 给你一个 无重复元素 的整数数组 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

2. 题目解析

- 题意分解

  1. 本题是计算多个集合之间的求和问题,每个集合由若干个同样的整数组成
  2. 同样整数和不能超过target,所以多个集合都是有限集合,因此每个集合能合成出来的数值也是有限的,可以用回溯法求解
  3. 回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。

- 优化思路

  1. 通常优化:减少循环层次

  2. 通常优化:增加分支,减少计算集

  3. 通常优化:采用内置算法来提升计算速度

  4. 分析题目特点,分析最优解

    1. 可以在回溯算法中使用值传递

    2. 可以在回溯算法中使用引用传递,但是应用传递必须解决回退操作,可以使用堆栈结构

    3. 可以考虑存储过程值列表,最后将等于target的集合返回


- 测量工具

  • 本地化测试说明:LeetCode网站测试运行时数据波动很大【可把页面视为功能测试】,因此需要本地化测试解决数据波动问题
  • CheckFuncPerf(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块
  • 本题本地化超时测试用例自己生成,详见章节【最优算法】,代码文件包含在【相关资源】中

3. 代码展开

1) 标准求解【值传递+回溯】

使用列表作为值传递参数,逐层递归,完成回溯

页面功能测试,马马虎虎,超过40%在这里插入图片描述

import CheckFuncPerf as cfp

class Solution:
 def combinationSum_base(self, candidates, target):
     def bracktracing(candidates, begin, ilen, path, ret, target):
         if target < 0:
             return
         if target == 0:
             ret.append(path)
             return
         for iIdx in range(begin, ilen):
             bracktracing(candidates, iIdx, ilen, path + [candidates[iIdx]], ret, 
                          target - candidates[iIdx])
     ilen = len(candidates)
     path, result = [], []
     if ilen == 0:
         return result
     bracktracing(candidates, 0, ilen, path, result, target)
     return result

aSolution = Solution()
result = cfp.getTimeMemoryStr(aSolution.combinationSum_base, nums, target)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))

# 运行结果
函数 combinationSum_base 的运行时间为 1076.25 ms;内存使用量为 12060.00 KB 执行结果 = 62271

2) 改进版一【引用传递+堆栈回溯】

使用列表作为引用传递参数,逐层递归,完成回溯

页面功能测试,马马虎虎,超越71%在这里插入图片描述

import CheckFuncPerf as cfp

class Solution:
 def combinationSum_ext1(self, candidates, target):
     candidates.sort()
     path, result = [], []
     idx, isum = 0, 0
     def bracktracing(idx, isum, path):
         if sum(path) == target:
             result.append(path[:])
             return
         for jIdx in range(idx, len(candidates)):
             if isum + candidates[jIdx] > target:
                 return
             path.append(candidates[jIdx])
             isum += candidates[jIdx]
             bracktracing(jIdx, isum, path)
             path.pop()
             isum -= candidates[jIdx]
     bracktracing(idx, isum, path)
     return result

aSolution = Solution()
result = cfp.getTimeMemoryStr(aSolution.combinationSum_base, nums, target)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))

# 运行结果
函数 combinationSum_base 的运行时间为 1076.25 ms;内存使用量为 12060.00 KB 执行结果 = 62271

3) 改进版二【过程值列表缓存+遍历后检索】

使用多维列表结构保存各数值对应的组合列表,遍历完成后下标检索对应组合列表

页面功能测试,马马虎虎,超过23%在这里插入图片描述

import CheckFuncPerf as cfp

class Solution:
 def combinationSum_ext2(self, candidates, target):
     import copy
     candidates.sort()
     dp = [[] for x in range(target + 1)]
     for candidate in candidates:
         for iIdx in range(candidate, target + 1):
             if candidate == iIdx:
                 dp[iIdx].append([candidate])
             else:
                 for combination in dp[iIdx - candidate]:
                     tmpgroup = copy.deepcopy(combination)
                     tmpgroup.append(candidate)
                     dp[iIdx].append(tmpgroup)
     return dp[target]

aSolution = Solution()
result = cfp.getTimeMemoryStr(aSolution.combinationSum_base, nums, target)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))

# 运行结果
函数 combinationSum_base 的运行时间为 1076.25 ms;内存使用量为 12060.00 KB 执行结果 = 62271

4. 最优算法

根据本地日志分析,最优算法为第1种方式【值传递+回溯】combinationSum_base

本题测试数据,似乎能推出以下结论:

  1. 组合的回溯求解中,值传递性能优于引用传递的堆栈结构
  2. 内存对象过多后,性能下降明显,如combinationSum_ext2
nums = [x for x in range(10, 20)]
target = 200
aSolution = Solution()
result = cfp.getTimeMemoryStr(aSolution.combinationSum_base, nums, target)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))
result = cfp.getTimeMemoryStr(aSolution.combinationSum_ext1, nums, target)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))
result = cfp.getTimeMemoryStr(aSolution.combinationSum_ext2, nums, target)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))

# 算法本地速度实测比较
函数 combinationSum_base 的运行时间为 1076.25 ms;内存使用量为 12060.00 KB 执行结果 = 62271
函数 combinationSum_ext1 的运行时间为 1243.29 ms;内存使用量为 11848.00 KB 执行结果 = 62271
函数 combinationSum_ext2 的运行时间为 14627.27 ms;内存使用量为 16080.00 KB 执行结果 = 62271

5. 相关资源

本文代码已上传到CSDN,地址:Python算法题源代码_LeetCode(力扣)_组合总和

一日练,一日功,一日不练十日空

may the odds be ever in your favor ~

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

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

相关文章

JVM运行流程

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;JavaEE &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; JVM 1. 运行流程2. 运行时数据区2.1 堆&am…

【精品】集合list去重

示例一&#xff1a;对于简单类型&#xff0c;比如String public static void main(String[] args) {List<String> list new ArrayList< >();list.add("aaa");list.add("bbb");list.add("bbb");list.add("ccc");list.add(…

C++——模板详解

目录 模板 函数模板 显示实例化 类模板 模板特点 模板 模板&#xff0c;就是把一个本来只能对特定类型实现的代码&#xff0c;变成一个模板类型&#xff0c;这个模板类型能转换为任何内置类型&#xff0c;从而让程序员只需要实现一个模板&#xff0c;就能对不同的数据进行操…

4.2 数据的描述性统计

1、总体规模的描述——总量指标 定义&#xff1a;反映在一定时间、空间条件下某种现象的总体规模、总水平或总成果的统计指标。 eg&#xff1a;营业额、利润等 2、总体规模的描述——相对指标 定义&#xff1a;两个有相互联系的指标数值之比 eg&#xff1a;目标完成率&…

GCN 翻译 - 1

ABSTRACT 我们提出了一种可扩展的在以图结构为基础的数据上的半监督学习&#xff0c;这种方法直接作用在图数据上&#xff0c;可以看做是卷积神经网络的变种。我们选择了图谱理论里面的一阶近似作为我们的卷积结构。我们的模型能够随着图的规模线性伸缩&#xff0c;并且隐藏层…

计算机专业大学四年应该如何规划(Java方向)

计算机专业的学生&#xff0c;如何在大学四年内提高自己的竞争力&#xff0c;毕业之后直接进大厂工作&#xff1f; 以下将从大学四年计算机专业的学习规划、课程设置、能力提升、参考书籍等方面&#xff0c;为同学们提供一些建议和指导。 大一&#xff1a; 主攻技能学习并且达…

枚举(蓝桥练习)(反倍数、特别数的和、找到最多的数、小蓝的漆房、小蓝和小桥的挑战)

目录 一、枚举算法介绍 二、解空间的类型 三、循环枚举解空间 四、例题 &#xff08;一、反倍数&#xff09; &#xff08;二、特别数的和&#xff09; &#xff08;三、找到最多的数&#xff09; &#xff08;四、小蓝的漆房&#xff09; &#xff08;五、小蓝和小桥的…

Linpmem:一款功能强大的Linux物理内存提取工具

关于Linpmem Linpmem是一款功能强大的Linux物理内存提取工具&#xff0c;该工具专为x64 Linux设计&#xff0c;可以帮助广大研究人员在执行安全分析过程中快速读取Linux物理内存数据。 该工具类似Windows下的Winpmem&#xff0c;Linpmem不是一个传统的内存转储工具&#xff0…

scons,一个实用的 Python 构建工具!

目录 前言 什么是SCons库&#xff1f; 安装SCons库 使用SCons库 SCons库的功能特性 1. 基于Python的构建描述语言 2. 自动化依赖管理 3. 多种构建环境支持 SCons库的应用场景 1. C/C项目构建 2. Python项目构建 3. 嵌入式系统开发 4. 持续集成环境 5. 跨平台项目构建 总…

如何实现无公网ip远程访问本地安卓Termux部署的MySQL数据库【内网穿透】

文章目录 前言1.安装MariaDB2.安装cpolar内网穿透工具3. 创建安全隧道映射mysql4. 公网远程连接5. 固定远程连接地址 前言 Android作为移动设备&#xff0c;尽管最初并非设计为服务器&#xff0c;但是随着技术的进步我们可以将Android配置为生产力工具&#xff0c;变成一个随身…

【InternLM 实战营笔记】大模型评测

随着人工智能技术的快速发展&#xff0c; 大规模预训练自然语言模型成为了研究热点和关注焦点。OpenAI于2018年提出了第一代GPT模型&#xff0c;开辟了自然语言模型生成式预训练的路线。沿着这条路线&#xff0c;随后又陆续发布了GPT-2和GPT-3模型。与此同时&#xff0c;谷歌也…

Failed to build tree: parent link [base_link] of joint [lidar_joint] not found

参考&#xff1a; Failed to build tree: parent link [base_link] of joint 在古月居gazebo 的基础教程里&#xff0c;运行古月居的mbot的launch文件报错&#xff0c;小机器人不出现。 主要原因是提供的xacro文件的宏定义没有放在xacro的命名空间。 解决&#xff1a; 将<mb…

Linux系统编程之线程互斥锁的使用方法

文章目录 一、Linux上线程开发互斥锁概要二、创建及销毁互斥锁2.1 示例&#xff1a;主线程等待两个线程退出&#xff0c;1线程和2线程打印信息 三、互斥量的初始化问题 一、Linux上线程开发互斥锁概要 互斥量&#xff08;mutex&#xff09;从本质上来说是一把锁&#xff0c;在…

小白水平理解面试经典题目leetcode 606. Construct String from Binary Tree【递归算法】

Leetcode 606. 从二叉树构造字符串 题目描述 例子 小白做题 坐在自习室正在准备刷题的小白看到这道题&#xff0c;想想自己那可是没少和白月光做题呢&#xff0c;也不知道小美刷题刷到哪里了&#xff0c;这题怎么还没来问我&#xff0c;难道是王谦谦去做题了&#xff1f; 这…

Dockerfile(6) - EXPOSE 指令详解

EXPOSE 通知 Docker 容器在运行时监听指定的网络端口 EXPOSE 端口号 EXPOSE 端口号/协议 默认协议是 TCP 同时在 TCP、UDP 上暴露端口 EXPOSE 80/tcp EXPOSE 80/udp EXPOSE 原理 个人理解&#xff1a;EXPOSE 暴露的端口更像是指明了该容器提供的服务需要用到的端口EXPOSE…

【比较mybatis、lazy、sqltoy、lambda、操作数据 】操作批量新增、分页查询

orm框架使用Lambda性能比较 环境&#xff1a; idea jdk17 spring boot 3.0.7 mysql 8.0测试条件常规对象 orm 框架是否支持xml是否支持 Lambda对比版本mybatis☑️☑️3.5.4sqltoy☑️☑️5.2.98lazy✖️☑️1.2.3-JDK17 数据库表(含有唯一性索引s_u) CREATE TABLE sys_u…

机器学习|线性回归

线性回归是尝试使用一条直线去拟合出图上的节点。 e i e_i ei​为第i个点构成的误差&#xff0c;使用平方的好处一是可以避免正负抵消&#xff0c;二是平方有利于放大大于1的误差的影响&#xff0c;同时缩小误差小于1的影响。 将平方项进行展开&#xff0c;以w作为变元&…

Floyd算法、Dijkstra算法、基础拓扑排序

Floyd算法 Dijkstra算法 基础拓扑排序

简单了解B树和B+树

目录 B树 B树 B树和B树的结构示意图 总结 B树和B树是两种非常重要的树状数据结构&#xff0c;它们广泛应用于数据库和文件系统的索引结构中。这两种数据结构能够帮助我们高效地管理、查询以及更新大量的数据。下面&#xff0c;我将简单介绍它们,以及他们之间的区别。 B树 B…

内存飙高问题如何排查?

目录 1、查看日志 2、查看GC情况 3、分析堆内存对象占用情况 4、分析堆内存快照文件 内存飙高如果发生在java进程上&#xff0c;一般情况是因为创建了大量对象导致&#xff0c;持续飙高说明垃圾回收跟不上对象创建的速度&#xff0c;或者内存泄漏导致对象无法被回收&#x…