题目
给你一个整数数组
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)
的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
思路
方法一(暴力方法,超时)
构建一个数组res
,其中第i
个元素res[i]
表示除 nums[i]
以外数组的乘积。例如对于数组 [1,2,3,4]
有:
res[0]: nums[1] * nums[2] * nums[3]res[1]: nums[0] * nums[2] * nums[3]res[2]: nums[0] * nums[1] * nums[3]res[3]: nums[0] * nums[1] * nums[2]
通过观察,我们可以将乘法分为两个部分,一部分是小于i
即 0~i - 1
元素乘积left
另外一部分是i + 1 ~ numsSize - 1
元素乘积 right
res[0]: 1* nums[1] * nums[2] * nums[3]res[1]: nums[0] * nums[2] * nums[3]res[2]: nums[0] * nums[1] * nums[3]res[3]: nums[0] * nums[1] * nums[2] * 1
那么 res[i] = left * right
这里最容易想到的方法就是遍历时计算出 0~i - 1
的乘积以及i + 1 ~ numsSize - 1
然后将两者相乘即可
代码实现
int* productExceptSelf(int* nums, int numsSize, int* returnSize) {
int* res = malloc(sizeof(int) * numsSize);
*returnSize = numsSize;
int i = 0, j = 0;
for (i = 0; i < numsSize; i++) {
int left = 1;
//求 0 ~ i - 1的元素乘积
for(j = 0; j <= i - 1; ++){
left *= nums[j];
}
int right = 1;
//求 i + 1 ~ numsSize 的元素乘积
for(j = i + 1; j < numsSize; j++){
right *= nums[j];
}
//二者相乘
res[i] = left * right;
}
return res;
}
方法二
根据方法一,观察可以发现:
res[0]: 1* nums[1] * nums[2] * nums[3]
res[1]: nums[0] * nums[2] * nums[3]
res[2]: nums[0] * nums[1] * nums[3]
res[3]: nums[0] * nums[1] * nums[2] * 1
我们可以定义一个left
让过程转换为:
left = 1
res[0]: left * nums[1] * nums[2] * nums[3] left = 1
res[1]: left * nums[2] * nums[3] left = 1*nums[0]
res[2]: left * nums[3] left = 1*nums[0] * nums[1]
res[3]: left * 1 left = 1*nums[0]*nums[1]*nums[2]
left
随着小标i
改变逐渐累积,而right
和left
相反,我们可以从后向前遍历,计算right
并将乘积保存到一个数组中
代码实现
int* productExceptSelf1(int* nums, int numsSize, int* returnSize) {
int* res = malloc(sizeof(int) * numsSize);
*returnSize = numsSize;
int i = 0;
int* right = malloc(sizeof(int) * numsSize);
right[numsSize - 1] = 1;
for (i = numsSize - 2; i >= 0; i--) {
right[i] = right[i + 1] * nums[i + 1];
}
int left = 1;
for (i = 0; i < numsSize; i++) {
res[i] = left * right[i];
left = left * nums[i];
}
free(right);
return res;
}