除自身以外数组的乘积(c++实现)
首先看题目:
给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中
除 nums[i] 之外其余各元素的乘积。
示例:
输入: [1,2,3,4]
输出: [24,12,8,6]
提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。
说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
进阶:
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/product-of-array-except-self
分析:
首先,如果用没有除法限制问题会简单很多,一次遍历求出数组的所有元素的乘积,然后再遍历一次将乘积除以元素,就是结果值。但是这样会存在两个问题:
- 1.如果有一个元素等于0,那该法失效
- 2.如果所有元素的乘积大于 INT_MAX,结果溢出数据也会不准确
实现思路:
既然题目提示了用前缀和后缀的乘积,那我们可以遍历数组,取每个元素的前缀元素乘积和后缀元素乘积,然后前后缀乘积再相乘即是结果,比如
数组:arr[0~n] , arr[1]除自身以外数组的乘积=(前缀乘积arr[0]) * (后缀乘积 arr[2]*…arr[n])
下面是实现代码:
vector<int> productExceptSelf(vector<int>& nums) {
int len = nums.size();
vector<int > res(len, 1);
vector<int > left(len, 1);
vector<int > right(len, 1);
for (int i = 1; i < len; i++) {
//注:arr[0] 没有前缀乘积默认为1, arr[len-1] 没有后缀乘积, 默认为1
left[i] = left[i - 1] * nums[i - 1]; //记录每个元素的前缀乘积
right[len - i - 1] = right[len - i] * nums[len - i]; 记录每个元素的后缀乘积
}
for (int i = 0; i < len; i++) {
res[i] = left[i] * right[i];
}
return res;
}
优化方案:
从代码可以看出,时间复杂度是O(n),空间复杂度是O(n),该法还有优化的空间,可将空间复杂度优化至O(1),即出输出数组res外,仅用常量级别空间;
思路是:先用res代替left存入每个元素的前缀乘积,第二次再用一个常量temp保存当前元素的后缀乘积,temp * res[i] 即是 arr[i]的.除自身以外数组的乘积。
下面是实现代码:
vector<int> productExceptSelf(vector<int>& nums) {
int len = nums.size();
vector<int > res(len, 1);
for (int i = 1; i < len; i++) {
res[i] = res[i - 1] * nums[i - 1]; //记录每个元素的前缀乘积
}
int temp = 1;
for (int i = len - 2; i >= 0; i--) {
temp *= nums[i + 1]; //记录当前元素的后缀乘积
res[i] = res[i] * temp; //当前元素的前缀乘积 * 当前元素的后缀乘积
}
return res;
}