刷爆力扣之构建乘积数组

简介: 刷爆力扣之构建乘积数组

一 🏠 题目描述

剑指 Offer 66. 构建乘积数组


给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B[i] 的值是数组 A 中除了下标 i 以外的元素的积, 即 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。


示例:


输入: [1,2,3,4,5]
输出: [120,60,40,30,24]

提示:


所有元素乘积之和不会溢出 32 位整数

a.length <=100000


二 🏠破题思路

2.1 🚀 关键信息

解决问题第一步,当然先提取题目字面上的关键信息 😎😎😎


题干简直超易理解,数组 B[0,1,…,n-1],其中 B[i] 的值是数组 A 中除了下标 i 以外的元素的积, 即 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]



看到这句的时候,各位看官大大应该和博主一样已经笑开了 🌸🌸🌸 吧


但是这道题的核心点是 不能使用除法 😖😖😖



提取完题目中的关键信息后,直接进入第二阶段,思路整理 😃😃😃



2.2 🚀 思路整理

如 2.1 所述,该题难点在于不能使用除法,即 只用乘法 生成数组 B


根据题目对 B[i] 的定义,可列表格,如下图所示


根据表格的主对角线(全为 1 ),可将表格分为 上三角 和 下三角 两部分;分别迭代计算下三角和上三角两部分的乘积,即可 不使用除法 就获得结果




三 🏠 代码详解

3.1 🚀 代码实现

按照我们刚才的破题思路,直接代码走起来 👇👇👇👇


std::vector<int> constructArr(std::vector<int>& a) {
  int len = a.size(); //输入数组长度
  std::vector<int> b(len, 1); //初始化输出数组 b
  int left =1, right =1; //初始化左右双指针
for (int i =0; i < len; ++i) { //遍历输入数组
  b[i] *= left; //left = 索引i位置左边所有数乘积, *= 赋值给 b[i]
  left *= a[i]; //索引i位置左边所有数乘积 * a[i]
  b[len -1- i] *= right; //right = 索引len-1-i位置右边所有数乘积, *= 赋值给 b[len-1-i]
  right *= a[len -1- i]; //索引len-1-i位置右边所有数乘积* a[len -1- i]
  }
  return b;
}


3.2 🚀 细节解析

看完 👀👀👀 全注释版的代码实现后,相信看官大大对整体逻辑已经是大写的 OK 了 😃😃😃


那么我们挖掘上述实现的晦涩细节 😖😖😖 进行解析,直接开干,走起来 👇👇👇👇


b[i] *= left; //left = 索引i位置左边所有数乘积, *= 赋值给 b[i]
left *= a[i]; //索引i位置左边所有数乘积 * a[i]

left 是索引 i 位置左边所有数乘积,*= 就是在把索引 i 位置左边所有数乘积赋值给 b[i]


left *= a[i] 为了一下循环(++i)提前计算 i 位置左边所有数乘积


那么这个过程就对应了,2.2 图示中的正三角过程(右部分的倒三角逻辑同理) 🌹🌹🌹



当然也可以使用两次循环,将正倒三角各元素乘积分开计算,在逻辑上或许会更好理解。但却多了一次遍历的开销,这里使用了双指针的操作(凡是等效逻辑正逆向遍历两次,均可使其简化为一次完成) 😜😜😜

四 🏠 心路历程

为方便各位看官大大了解博主真实刷题过程,我把当时状态纯纯真实还原,记录在心路历程这一小节,不感兴趣的小伙伴可以直接跳过哈


博主在第一阶段提取 🚀 关键信息并没有问题,在第二阶段 🚀 思路整理中有考虑尝试使用双指针,但是未联想到 上三角 和 下三角(破题关键点)😭😭😭


所以博主的这道题是在阅读完官方解析后,解出来并加以记录的


相关文章
|
1月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
38 0
|
3月前
|
算法
LeetCode第53题最大子数组和
LeetCode第53题"最大子数组和"的解题方法,利用动态规划思想,通过一次遍历数组,维护到当前元素为止的最大子数组和,有效避免了复杂度更高的暴力解法。
LeetCode第53题最大子数组和
|
1月前
【LeetCode-每日一题】 删除排序数组中的重复项
【LeetCode-每日一题】 删除排序数组中的重复项
19 4
|
1月前
|
索引
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
18 0
Leetcode第三十三题(搜索旋转排序数组)
|
1月前
|
算法 C++
Leetcode第53题(最大子数组和)
这篇文章介绍了LeetCode第53题“最大子数组和”的动态规划解法,提供了详细的状态转移方程和C++代码实现,并讨论了其他算法如贪心、分治、改进动态规划和分块累计法。
56 0
|
1月前
|
C++
【LeetCode 12】349.两个数组的交集
【LeetCode 12】349.两个数组的交集
16 0
|
3月前
|
算法
LeetCode第81题搜索旋转排序数组 II
文章讲解了LeetCode第81题"搜索旋转排序数组 II"的解法,通过二分查找算法并加入去重逻辑来解决在旋转且含有重复元素的数组中搜索特定值的问题。
LeetCode第81题搜索旋转排序数组 II
|
2月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
55 6
|
3月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
113 2