Python算法题集_除自身以外数组的乘积

 Python算法题集_除自身以外数组的乘积

  • 题239:除自身以外数组的乘积
  • 1. 示例说明
  • 2. 题目解析
    • - 题意分解
    • - 优化思路
    • - 测量工具
  • 3. 代码展开
    • 1) 标准求解【暴力求解】
    • 2) 改进版一【字典改进乘积计算】
    • 3) 改进版二【字典改进乘积计算+预计算数字乘积】
    • 4) 改进版三【前缀乘积+后缀乘积】
    • 5) 改进版四【前缀乘积+后缀乘积+一次性分配内存】
    • 6) 改进版五【改进空间复杂度】
  • 4. 最优算法

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

题239:除自身以外数组的乘积

1. 示例说明

  给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积
  题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
  请 不要使用除法, 且在 O(*n*) 时间复杂度内完成此题。

示例 1:

输入: nums = [1,2,3,4]
输出: [24,12,8,6]

示例 2:

输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

提示:

  • 2 <= nums.length <= 105
  • -30 <= nums[i] <= 30
  • 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内
  • 进阶: 你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组 不被视为 额外空间。)

2. 题目解析

- 题意分解

  1. 本题为求所有子数组的乘积
  2. 本题的主要计算有2处,1是子数组遍历,2是子数组求乘积
  3. 基本的办法是双层循环,挨个计算,所以基本的时间算法复杂度为O(n2)

- 优化思路

  1. 减少循环层次

  2. 增加分支,减少计算集

  3. 采用内置算法来提升计算速度

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

    1)采用字典存储数组中每个数字的数量,可以加快子数组求乘积的速度

    2)将字典中每个数字的乘积、少乘一次的乘积先计算出来,改计算为字典查询,可以加快子数组求乘积的速度

    3)采用类似前缀和的思路,计算前缀乘积、后缀乘积,这样第i个元素的除自身外数组的乘积=前缀乘积i-1 * 后缀乘积i+1,可以减少循环层次

    4)进阶算法要求少用临时空间,使用结果数组和原始数组,可以配合完成结果计算


- 测量工具

  • 本地化测试说明:LeetCode网站测试运行时数据波动很大,因此需要本地化测试解决这个问题
  • CheckFuncPerf(函数用时和内存占用测试模块)已上传到CSDN,地址在这里:Python算法题集_检测函数用时和内存占用的模块
  • 测试的超时测试用例文件是官网的,已上传到CSDN,地址在这里:力扣算法题:除自身以外数组的乘积,测试超时数组,长度5W

3. 代码展开

1) 标准求解【暴力求解】

双层循环,超时未过

import CheckFuncPerf as cfpdef productExceptSelf_base(nums):result = []for iIdx in range(len(nums)):imulti = 1for jIdx in range(len(nums)):if jIdx!= iIdx:imulti *= nums[jIdx]result.append(imulti)return resulttestcase_big = open(r'testcase/hot16_big.txt', mode='r', encoding='utf-8').read().replace('[', '').replace(']', '')
testcase_big = testcase_big.split(',')
nums = [int(x) for x in testcase_big]
result = cfp.getTimeMemoryStr(productExceptSelf_ext1, nums)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))# 运行结果
函数 productExceptSelf_base 的运行时间为 194010.75 ms;内存使用量为 2348.00 KB 执行结果 = 50000

2) 改进版一【字典改进乘积计算】

尴尬的双层循环 尴尬通过,超过5%在这里插入图片描述

import CheckFuncPerf as cfpdef productExceptSelf_ext1(nums):dic_nums = {}for iIdx in range(len(nums)):dic_nums[nums[iIdx]] = dic_nums.get(nums[iIdx], 0) + 1result = []for iIdx in range(len(nums)):imulti = 1for aKey in dic_nums.keys():if aKey != nums[iIdx]:imulti *= aKey ** dic_nums[aKey]else:imulti *= aKey ** (dic_nums[aKey]-1)result.append(imulti)return resulttestcase_big = open(r'testcase/hot16_big.txt', mode='r', encoding='utf-8').read().replace('[', '').replace(']', '')
testcase_big = testcase_big.split(',')
nums = [int(x) for x in testcase_big]
result = cfp.getTimeMemoryStr(productExceptSelf_ext1, nums)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))# 运行结果
函数 productExceptSelf_ext1 的运行时间为 90.02 ms;内存使用量为 1944.00 KB 执行结果 = 50000

3) 改进版二【字典改进乘积计算+预计算数字乘积】

改进版,然并卵,还是双层循环 微小改进,超过17%在这里插入图片描述

import CheckFuncPerf as cfpdef productExceptSelf_ext2(nums):dic_nums = {}for iIdx in range(len(nums)):dic_nums[nums[iIdx]] = dic_nums.get(nums[iIdx], [0, 1, 1])dic_nums[nums[iIdx]][0] += 1for aKey in dic_nums.keys():dic_nums[aKey][1] = int(aKey ** (dic_nums[aKey][0]-1))dic_nums[aKey][2] = int(aKey ** dic_nums[aKey][1])result = []for iIdx in range(len(nums)):imulti = 1for bKey in dic_nums.keys():if bKey != nums[iIdx]:imulti *= dic_nums[bKey][2]else:imulti *= dic_nums[bKey][1]result.append(imulti)return resulttestcase_big = open(r'testcase/hot16_big.txt', mode='r', encoding='utf-8').read().replace('[', '').replace(']', '')
testcase_big = testcase_big.split(',')
nums = [int(x) for x in testcase_big]
result = cfp.getTimeMemoryStr(productExceptSelf_ext2, nums)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))# 运行结果
函数 productExceptSelf_ext2 的运行时间为 46.00 ms;内存使用量为 924.00 KB 执行结果 = 50000

4) 改进版三【前缀乘积+后缀乘积】

不再是双层循环,指标改进显著 指标优异,超越94%在这里插入图片描述

import CheckFuncPerf as cfpdef productExceptSelf_ext3(nums):leftmultilist, rightmultilist = [1] * len(nums), [1] * len(nums)leftmulti, rightmulti = 1, 1for iIdx in range(len(nums)):leftmulti *= nums[iIdx]rightmulti *= nums[-iIdx-1]leftmultilist[iIdx] = leftmultirightmultilist[-iIdx-1] = rightmultiresult = [rightmultilist[1]]for iIdx in range(1, len(nums)-1):result.append(leftmultilist[iIdx-1]*rightmultilist[iIdx+1])result.append(leftmultilist[len(nums)-2])return resulttestcase_big = open(r'testcase/hot16_big.txt', mode='r', encoding='utf-8').read().replace('[', '').replace(']', '')
testcase_big = testcase_big.split(',')
nums = [int(x) for x in testcase_big]
result = cfp.getTimeMemoryStr(productExceptSelf_ext3, nums)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))# 运行结果
函数 productExceptSelf_ext3 的运行时间为 22.00 ms;内存使用量为 2332.00 KB 执行结果 = 50000

5) 改进版四【前缀乘积+后缀乘积+一次性分配内存】

直接分配结果集内存,不是一个元素一个元素的分配,实测有效 飞龙在天,超越97%在这里插入图片描述

import CheckFuncPerf as cfpdef productExceptSelf_ext4(nums):leftmultilist, rightmultilist, result = [1] * len(nums), [1] * len(nums), [1] * len(nums)leftmulti, rightmulti = 1, 1for iIdx in range(len(nums)):leftmulti *= nums[iIdx]rightmulti *= nums[-iIdx - 1]leftmultilist[iIdx] = leftmultirightmultilist[-iIdx - 1] = rightmultiresult[0] = rightmultilist[1]for iIdx in range(1, len(nums) - 1):result[iIdx] = leftmultilist[iIdx - 1] * rightmultilist[iIdx + 1]result[-1] = leftmultilist[len(nums) - 2]return resulttestcase_big = open(r'testcase/hot16_big.txt', mode='r', encoding='utf-8').read().replace('[', '').replace(']', '')
testcase_big = testcase_big.split(',')
nums = [int(x) for x in testcase_big]
result = cfp.getTimeMemoryStr(productExceptSelf_ext4, nums)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))# 运行结果
函数 productExceptSelf_ext4 的运行时间为 21.00 ms;内存使用量为 2252.00 KB 执行结果 = 50000

6) 改进版五【改进空间复杂度】

不使用前缀乘积和后缀乘积数组,使用传入数组和结果数组直接计算,节省了内存分配环节,是本文最优的算法

网站波动,虚伪的95%在这里插入图片描述

import CheckFuncPerf as cfpdef productExceptSelf_ext5(nums):result = [1] * len(nums)for iIdx in range(1, len(nums)):result[iIdx] = result[iIdx-1] * nums[iIdx-1]iright = 1for iIdx in range(1, len(nums)):iright *= nums[-iIdx]result[-iIdx-1] = result[-iIdx-1] * irightreturn resulttestcase_big = open(r'testcase/hot16_big.txt', mode='r', encoding='utf-8').read().replace('[', '').replace(']', '')
testcase_big = testcase_big.split(',')
nums = [int(x) for x in testcase_big]
result = cfp.getTimeMemoryStr(productExceptSelf_ext5, nums)
print(result['msg'], '执行结果 = {}'.format(len(result['result'])))# 运行结果
函数 productExceptSelf_ext5 的运行时间为 18.01 ms;内存使用量为 1856.00 KB 执行结果 = 50000

4. 最优算法

根据本地日志分析,最优算法为第6种productExceptSelf_ext5

testcase_big = open(r'testcase/hot16_big.txt', mode='r', encoding='utf-8').read().replace('[', '').replace(']', '')
testcase_big = testcase_big.split(',')
nums = [int(x) for x in testcase_big]# 6种算法本地速度实测比较    ⇒   最优算法为第6种
函数 productExceptSelf_base 的运行时间为 194010.75 ms;内存使用量为 2348.00 KB 执行结果 = 50000
函数 productExceptSelf_ext1 的运行时间为 90.02 ms;内存使用量为 1944.00 KB 执行结果 = 50000
函数 productExceptSelf_ext2 的运行时间为 46.00 ms;内存使用量为 924.00 KB 执行结果 = 50000
函数 productExceptSelf_ext3 的运行时间为 22.00 ms;内存使用量为 2332.00 KB 执行结果 = 50000
函数 productExceptSelf_ext4 的运行时间为 21.00 ms;内存使用量为 2252.00 KB 执行结果 = 50000
函数 productExceptSelf_ext5 的运行时间为 18.01 ms;内存使用量为 1856.00 KB 执行结果 = 50000

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

may the odds be ever in your favor ~

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

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

相关文章

第二集《修道宗范》

请大家打开讲义第5页&#xff0c;我们讲到丙一、先修出离心。 身为一个有情众生&#xff0c;我们内心当中&#xff0c;有一个没办法改变的本性&#xff0c;我们就是希望生命能够离苦得乐&#xff0c;这是没办法改变的。换句话说&#xff0c;我们每一个人都喜欢安乐&#xff0c…

代码随想录算法训练营Day20|最大二叉树、合并二叉树、二叉搜索树中的搜索、验证二叉搜索树

最大二叉树 题目&#xff1a; 最大二叉树定义&#xff1a; 二叉树的根是数组中的最大元素 左子树是通过数组中最大值左边部分构造出的最大二叉树。 右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构建最大二叉树&#xff0c;并且输出这个树的节点…

【JavaScript】Generator

MDN-Generator Generator对象由生成器函数返回&#xff0c;并且它符合可迭代协议和迭代器协议。 Generator-核心语法 核心语法: 定义生成器函数获取generator对象yield表达式的使用通过for of获取每一个yield的值 // 1. 通过function* 创建生成器函数 function* foo() {//…

Unity DOTween插件常用方法(一)

文章目录 1.1 控制Api1.2 动画Api 1.1 控制Api DOKill DOKill表示停止该物体上所有的Tween动画。DOTween可以同时运行多个Tween&#xff0c;如果需要停止所有正在运行的Tween&#xff0c;可以使用这个方法; 还有一种使用场景&#xff0c;即反复打开某一视图&#xff0c;而该视…

Java技术栈 —— Hadoop入门(二)实战

Java技术栈 —— Hadoop入门&#xff08;二&#xff09; 一、用MapReduce对统计单词个数1.1 项目流程1.2 可能遇到的问题1.3 代码勘误1.4 总结 一、用MapReduce对统计单词个数 1.1 项目流程 (1) 上传jar包。 (2) 上传words.txt文件。 (3) 用hadoop执行jar包的代码&#xff0c;…

【C++】 C++入门 — auto关键字

C入门 auto 关键字1 介绍2 使用细则3 注意事项 Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读下一篇文章见&#xff01;&#xff01;&#xff01; auto 关键字 1 介绍 编程时常常需要把表达式的值赋给变量&#xff0c;这就要求在声明变量时清楚地知道表达式的类…

56-主,回调函数,回调函数的参数传参,函数和变量的公私有,特权方法,立即执行函数,闭包(解除引用)

1.回调函数 定义了函数,没有调用函数,但最终执行了。 <script>//回调函数// 定时器setInterval(function(){console.log("a")},1000)// 延迟器setTimeout(function(){console.log("a")},3000)</script> 2.将实参变为函数,将person方法作为…

什么是多态?它和重载有什么区别?

前言 大家好&#xff0c;我是chowley&#xff0c;相信学过编程语言的你&#xff0c;肯定听说过多态和重载两个概念&#xff0c;可多数人对他们之间的区别还是不太清晰&#xff0c;导致同时听到两个词一起出现时会大脑空白&#xff0c;今天我就来详细的介绍一下二者的区别&…

指针的深入理解(四)

这节主要讨论sizeof和strlen的区别&#xff0c;以及一些理解题。 sizeof 求的是对象的大小&#xff0c;深入理解一点就是&#xff1a;这个对象&#xff0c;他一定有一块对应的内存空间。求的就是这一块内存空间。 strlen 只能用来求字符串&#xff0c; 求取的是字符串的长度。…

面试了字节大模型算法岗(实习),快被问哭了。。。。

最近技术群组织了一次算法面试讨论会&#xff0c;今天分享的是一位小伙子的痛苦面试经历&#xff0c;如果你想加入我们的讨论群&#xff0c;见文末。 本次分享的内容如下&#xff1a; 应聘岗位&#xff1a;字节大模型算法实习生 面试轮数&#xff1a;第一轮 整体面试感觉&…

python封装的.exe文件是如何在cmd中获取.xml路径的?

这段日子搞项目算法封装&#xff0c;愁死我。来回改了三遍&#xff0c;总算把相对路径、绝对路径&#xff0c;还有cmd给.exe传参的方式搞懂了。 主要是这个语句 workspace sys.argv[1] sys.argv[]的作用就是,在运行python文件的时候从外部输入参数往文件里面传递参数。 外部就…

CTF盲水印工具:Blind-WaterMark安装

工具下载地址&#xff1a;GitCode - 开发者的代码家园 下载完毕后&#xff0c;只留这些东西就行 接下来需要安装两个依赖&#xff1a; opencv、matplotlib 直接pip install安装的话&#xff0c;工具使用会报错 所以需要到网站里挑选适合的版本进行安装 下载地址&#xff1…

项目:博客

1. 运行环境&#xff1a; 主机 主机名 系统 服务 192.168.223.129 Server_Web Linux Web 192.168.48.131 Server-NFS-DNS Linux NFS/DNS 2. 基础配置 配置主机名&#xff0c;静态IP地址 开启防火墙并配置 部分开启SElinux并配置 服务器之间使用同ntp.aliyun.com进行…

代码随想录算法训练营第二十二天|235. 二叉搜索树的最近公共祖先 ● 701.二叉搜索树中的插入操作 ● 450.删除二叉搜索树中的节点

235. 二叉搜索树的最近公共祖先 发现规律&#xff1a; 当我们从上向下去递归遍历&#xff0c;第一次遇到 cur节点是数值在[p, q]区间中&#xff0c;那么cur就是p和q的最近公共祖先。 class Solution { public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, Tr…

在JVM中,Java对象是如何创建、存储和访问的?

在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;Java对象的创建、存储和访问是Java程序运行的核心部分。这个过程涉及到内存管理、对象模型以及运行时数据区域的概念。 1. Java对象的创建&#xff1a; a. 类加载&#xff1a; 在Java程序运行时&#xff0c;类加载器负…

详讲api网关之kong的基本概念及安装和使用(二)

consul的服务注册与发现 如果不知道consul的使用&#xff0c;可以点击上方链接&#xff0c;这是我写的关于consul的一篇文档。 upstreamconsul实现负载均衡 我们知道&#xff0c;配置upstream可以实现负载均衡&#xff0c;而consul实现了服务注册与发现&#xff0c;那么接下来…

C++算法学习心得七.贪心算法(1)

1.贪心算法理论基础 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。贪心算法并没有固定的套路&#xff0c;唯一的难点就是如何通过局部最优&#xff0c;推出整体最优。最好用的策略就是举反例&#xff0c;如果想不到反例&#xff0c;那么就试一试贪心吧 贪…

leetcode209长度最小的子数组|滑动窗口算法详细讲解学习

滑动窗口是一种基于双指针的一种思想&#xff0c;两个指针指向的元素之间形成一个窗口。 分类&#xff1a;窗口有两类&#xff0c;一种是固定大小类的窗口&#xff0c;一类是大小动态变化的窗口。 简而言之&#xff0c;滑动窗口算法在一个特定大小的字符串或数组上进行操作&…

DevEco Studio 保存自动格式化代码

目标&#xff1a;保存后自动格式化代码 单次快捷键&#xff1a;Ctrl Alt L 步骤一 步骤二

7.2、子集求和问题与背包密码系统

7.2、子集求和问题与背包密码系统 一、数学描述 1.1、第一种描述 20 世纪 70 年代末&#xff0c;默克尔和赫尔曼首次尝试将密码系统建立在一个 NP-完全问题上。他们使用了以下数学问题的一个版本&#xff0c;该问题是对经典knapsack问题的概括。 子集和问题 假设你有一个正…