携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
题目
给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
实例
输入: [1,2,3,4] 输出: [24,12,8,6]
说明
提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。 说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
思路
相信聪明的小伙伴们,其实一看题目是一个简单的题目,就是简单的循环先求整个数组的成绩,最后再除以自身不就是得出了答案吗!大家是不是都这么想的!其实在说明中已经体现出来了.请不要使用除法,且在 O(n) 时间复杂度内完成此题。 那么你的想法可就不行了!既然这样我们得换一种思路解题! 怎么解呢?我们要求的是除自身以外的乘积,那么我们就不乘自身嘛,直接乘其他的数据(不包括自身).是不是就满足题意了呢!! 我们开始开拓自己的思维:
- 我们用两个数组(一个左数组一个右数组),分别存储这个数X左边数的乘积和X右边数的乘积.
- 得到了这两个数组后,我们直接对应相乘两个数组,不就得到了我们要的结果!!
是不是很简单,就两行的思路!!
代码
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int length = nums.size();
// L 和 R 分别表示左右两侧的乘积列表
vector<int> L(length, 0), R(length, 0);
vector<int> answer(length);
// L[i] 为索引 i 左侧所有元素的乘积
// 对于索引为 '0' 的元素,因为左侧没有元素,所以 L[0] = 1
L[0] = 1;
for (int i = 1; i < length; i++) {
L[i] = nums[i - 1] * L[i - 1];
}
// R[i] 为索引 i 右侧所有元素的乘积
// 对于索引为 'length-1' 的元素,因为右侧没有元素,所以 R[length-1] = 1
R[length - 1] = 1;
for (int i = length - 2; i >= 0; i--) {
R[i] = nums[i + 1] * R[i + 1];
}
// 对于索引 i,除 nums[i] 之外其余各元素的乘积就是左侧所有元素的乘积乘以右侧所有元素的乘积
for (int i = 0; i < length; i++) {
answer[i] = L[i] * R[i];
}
return answer;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/product-of-array-except-self/solution/chu-zi-shen-yi-wai-shu-zu-de-cheng-ji-by-leetcode-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
我事先说明一下这不是我的思路,但是我觉得官方的思路有学习的地方,适合初步进行理解.仅此而已!我并没有抄!
接下来到了进阶环境(我们会成长题目肯定也会啊)
进阶
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
啊哦,这个进阶就告诉了我们不能用两个数组,只能用一个而且这个还必须是输出数组.常数空间复杂度就是O(1) 我们还是老的一套思路,只不过因为进阶,我们需要进行优化,减少空间复杂度.
- 既然题目要求只能在常数空间复杂度内也就是只能定义变量,不能用
数组杀器,我们定义left和right代替我们上诉的数组. - 我们还是需要X左边数的乘积,但是left有缺陷不能存储之前的数只能覆盖,right也一样,我们就直接一点,把left和right当做指针(并不是真的指针,一种话的描述),从两头出发,当他们有相交的地方了,就相乘,不得到了我要的数吗!
如果你还不能理解,那么看以下图:
代码
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
vector<int> res(nums.size() , 1);
int n=nums.size();
int left=1;
int right=1;
for(int i=0;i<nums.size();i++)
{
res[i]*=left;
left*=nums[i];//左边数乘积
res[n - 1 - i] *= right;
right=right*nums[nums.size()-1-i];//右边数乘积
//cout<<res[i]<<" "<<res[nums.size() - 1 - i]<<endl;
//测试思路
}
return res;
}
};