当前位置: 首页 > news >正文

【Day 11】238.除自身以外数组的乘积

文章目录

  • 238.除自身以外数组的乘积
  • 题目:
  • 思路:
  • 举例:
    • 方法一(原始思路,需要 L 和 R 两个数组)
    • 方法二(优化后,只用一个数组 + 一个变量 R)
      • 第一步:计算左边乘积 L,存到 ans
      • 第二步:再从右往左乘上右边积
  • 代码实现(Go):
    • 优化前:
    • 优化后:

238.除自身以外数组的乘积

题目:

给你一个整数数组 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
输入 保证 数组 answer[i] 在 32 位 整数范围内


思路:

利用索引左侧所有数字的乘积和右侧所有数字的乘积(即前缀积与后缀积)相乘得到答案。

  1. 初始化两个空数组 L R。对于给定索引 i,L[i] 代表的是 i 左侧所有数字的乘积R[i] 代表的是 i 右侧所有数字的乘积
  2. 需要用两个循环来填充 L 和 R 数组的值。
    对于数组 L,L[0] 应该是 1,因为第一个元素的左边没有元素
    对于其他元素:L[i] = L[i-1] * nums[i-1]

当前位置 i 的左边积,等于它前一个位置的左边积,再乘上前一个位置的数。

  1. 同理,对于数组 R,R[length-1] 应为 1。length 指的是输入数组的大小。
    其他元素:R[i] = R[i+1] * nums[i+1]

当前位置 i 的右边积,等于它后一个位置的右边积,再乘上后一个位置的数。

  1. 当 R 和 L 数组填充完成,只需要在输入数组上迭代,且索引 i 处的值为:L[i] * R[i]

缺点:需要 O(n) 额外空间存储 L 和 R。

优化:只使用一个结果数组 ans,且不存储R数组,空间 O(1)。

L[i] 必须从左往右计算,所以可以先一边遍历一边计算好,放到 ans 里。(前缀积)
R[i] 必须从右往左计算,但其实不需要数组存下来,只要用一个变量 R 滚动维护右边乘积即可。(后缀积)

  1. 第一次从左往右遍历算出所有 L[i] 并存到 ans 数组里
    此时 ans[i] = L[i]
  2. 再从右往左遍历用一个变量 R 维护右边的乘积,不断更新
    每次让 ans[i] *= R(即在已有的左边积上再乘上右边积)。
    然后更新 R *= nums[i](让 R 包含当前位置的数,为下一步准备)。

举例:

假设:输入数组 nums = [1, 2, 3, 4],

方法一(原始思路,需要 L 和 R 两个数组)

  1. 先算左边乘积 L:
  • L[0] = 1(因为 0 左边没有数)
  • L[1] = L[0] * nums[0] = 1 * 1 = 1
  • L[2] = L[1] * nums[1] = 1 * 2 = 2
  • L[3] = L[2] * nums[2] = 2 * 3 = 6
    → L = [1, 1, 2, 6]
  1. 再算右边乘积 R:
  • R[3] = 1(因为最后一个数右边没有数)
  • R[2] = R[3] * nums[3] = 1 * 4 = 4
  • R[1] = R[2] * nums[2] = 4 * 3 = 12
  • R[0] = R[1] * nums[1] = 12 * 2 = 24
    → R = [24, 12, 4, 1]
  1. 最终结果 ans:
  • ans[i] = L[i] * R[i]
    → ans = [24, 12, 8, 6]

方法二(优化后,只用一个数组 + 一个变量 R)

第一步:计算左边乘积 L,存到 ans

  • 初始化 ans[0] = 1
  • ans[1] = ans[0] * nums[0] = 1 * 1 = 1
  • ans[2] = ans[1] * nums[1] = 1 * 2 = 2
  • ans[3] = ans[2] * nums[2] = 2 * 3 = 6
    → 此时 ans = [1, 1, 2, 6](其实就是 L)

第二步:再从右往左乘上右边积

  • 初始化 R = 1
  • i=3:ans[3] = ans[3] * R = 6 * 1 = 6;更新 R = R * nums[3] = 1 * 4 = 4
  • i=2:ans[2] = ans[2] * R = 2 * 4 = 8;更新 R = 4 * 3 = 12
  • i=1:ans[1] = ans[1] * R = 1 * 12 = 12;更新 R = 12 * 2 = 24
  • i=0:ans[0] = ans[0] * R = 1 * 24 = 24;更新 R = 24 * 1 = 24(用不到了)
    → 最终 ans = [24, 12, 8, 6]

代码实现(Go):

详细注解:

优化前:

// package main// import "fmt"func productExceptSelf(nums []int) []int {n := len(nums)L := make([]int, n) // L[i]: i 左侧所有元素的乘积R := make([]int, n) // R[i]: i 右侧所有元素的乘积ans := make([]int, n)// 计算左侧乘积 LL[0] = 1for i := 1; i < n; i++ {L[i] = L[i-1] * nums[i-1]}// 计算右侧乘积 RR[n-1] = 1for i := n - 2; i >= 0; i-- {R[i] = R[i+1] * nums[i+1]}// 组合答案:ans[i] = 左乘积 * 右乘积for i := 0; i < n; i++ {ans[i] = L[i] * R[i]}return ans
}// func main() {
// 	fmt.Println(productExceptSelf([]int{1, 2, 3, 4})) // 输出[24 12 8 6]
// }

优化后:

// package main// import "fmt"func productExceptSelf(nums []int) []int {n := len(nums)ans := make([]int, n) // 结果数组(通常不计入额外空间)// 1) 先写入“左边乘积”:ans[i] = nums[0..i-1] 的乘积// 最左边 i=0 的左侧没有元素,乘法单位元为 1ans[0] = 1for i := 1; i < n; i++ {// ans[i-1] 已经是 nums[0..i-2] 的乘积,// 乘上 nums[i-1] 就得到 nums[0..i-1] 的乘积ans[i] = ans[i-1] * nums[i-1]}// 2) 再从右往左,用滚动变量 R 记录“右边乘积”// 初始时最右端右侧无元素,因此取 1R := 1for i := n - 1; i >= 0; i-- {// 循环从 i = n-1(最后一个位置)开始// 当前 ans[i](左边乘积)乘上右边乘积 R,即为最终答案ans[i] = ans[i] * R// 把当前元素并入右边乘积,供左边的下一个 i-1 使用R *= nums[i]}return ans
}// func main() {
// 	fmt.Println(productExceptSelf([]int{1, 2, 3, 4})) // 输出[24 12 8 6]
// }

无注释(优化后):

package mainimport "fmt"func productExceptSelf(nums []int) []int {n := len(nums)ans := make([]int, n)ans[0] = 1for i := 1; i < n; i++ {ans[i] = ans[i-1] * nums[i-1]}R := 1for i := n - 1; i >= 0; i-- {ans[i] *= RR *= nums[i]}return ans
}func main() {fmt.Println(productExceptSelf([]int{1, 2, 3, 4})) // 输出[24 12 8 6]
}

http://www.dtcms.com/a/346778.html

相关文章:

  • Trae 编辑器在 Python 环境缺少 Pylance,怎么解决
  • 构建现代高并发服务器:从内核机制到架构实践
  • Spring把「手动」的复杂裹成了「自动」的温柔
  • PostgreSQL15——查询详解
  • 【51单片机】【protues仿真】基于51单片机宠物投食器系统
  • Qt图像裁剪实时显示尺寸实现
  • Qt5 高级功能
  • 当 AI 学会 “理解” 人类:自然语言处理的进化与伦理边界
  • 商品与股指类ETF期权买卖五档Tick分钟级历史行情数据分析
  • 【KO】前端面试三
  • GPT-5:天变了吗?还是风停了?
  • 基于Python的农作物病虫害防治网站 Python+Django+Vue.js
  • MySQL奔溃,InnoDB文件损坏修复记录
  • [2025CVPR-目标检测方向]PointSR:用于无人机视图物体检测的自正则化点监控
  • 尤弥尔传奇能够进行挂机搬砖吗?
  • AI实现超级客户端打印 支持APP 网页 小程序 调用本地客户端打印
  • 爬小红书图片软件:根据搜索关键词,采集笔记图片、正文、评论等
  • Angular初学者入门第三课——工厂函数(精品)
  • 游戏广告投放数据分析项目:拆解投放的“流量密码”
  • kail的浏览器连接不上网
  • 20250823给荣品RD-RK3588开发板刷Rockchip原厂的Buildroot【linux-5.10】时调通AP6275P的WIFI【源码部分】
  • 从 M4S 到 MP4:用 FFmpeg 轻松合并音视频文件
  • 达梦数据库统计信息收集
  • 无人机光伏巡检误检率↓79%!陌讯多模态融合算法在组件缺陷检测的落地优化
  • 【85页PPT】数字化转型LIMS大型企业智能制造之LIMS实验室管理系统产品解决方案(附下载方式)
  • webrtc弱网-SendSideBandwidthEstimation类源码分析与算法原理
  • 使用dism++备份系统时,出现“句柄无效”错误的解决方法
  • 重构实训生态:旅游管理虚拟仿真实训室的标准落地与价值创新
  • 某电器5G智慧工厂网络建设全解析
  • 【ABAP4】创建Package